Structure

The Structure class in QDK/Chemistry represents a molecular structure, which always includes 3D coordinates and element information, and optionally includes related properties like atomic masses and nuclear charges. As a core data class, it follows QDK/Chemistry’s immutable data pattern.

Overview

The Structure class is a fundamental data container in QDK/Chemistry that represents the geometric arrangement of atoms in a molecular system. It provides the foundation for all quantum chemistry calculations by defining the nuclear framework on which electronic structure calculations are performed.

Properties

Coordinates

3D Cartesian coordinates for each atom

Elements

Chemical elements of the atoms

Masses

Atomic masses of each of the atoms

Nuclear charges

Nuclear charges (atomic numbers) of each of the atoms

Units

All internal coordinates in the Structure class are in Bohr by default. This applies to all methods that return or accept coordinates. The only time Angstrom units can be found by default is in the xyz file format, where Angstrom is default (see below).

Usage

The Structure class is typically the starting point for any calculation workflow in QDK/Chemistry. It is used to define the molecular system before performing electronic structure calculations.

Note

Coordinates are in Bohr by default when creating or importing a Structure. See the Units section below for more details on unit conversions.

Creating a structure object

A Structure object can be created by specifying coordinates explicitly (in Bohr):

#include <qdk/chemistry.hpp>
using namespace qdk::chemistry::data;

int main() {
  // Specify a structure using coordinates (in Bohr), and either symbols or
  // elements
  std::vector<Eigen::Vector3d> coords = {{0.0, 0.0, 0.0},
                                         {0.0, 0.0, 1.4}};  // Bohr
  std::vector<std::string> symbols = {"H", "H"};

  Structure structure(coords, symbols);

  // Equivalent to 'structure', but uses 'elements' instead of 'symbols'
  std::vector<Element> elements = {Element::H, Element::H};
  Structure structure_alternative(coords, elements);

  // Another variation on construction: can specify custom masses and/or charges
  std::vector<double> custom_masses{1.001, 0.999};
  std::vector<double> custom_charges = {0.9, 1.1};
  Structure structure_custom(coords, elements, custom_masses, custom_charges);
import numpy as np
from pathlib import Path
from qdk_chemistry.data import Structure, Element

# Specify a structure using coordinates (in Bohr), and either symbols or elements
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])  # Bohr
symbols = ["H", "H"]

structure = Structure(coords, symbols=symbols)

# Equivalent to 'structure', but uses 'elements' instead of 'symbols'
elements = [Element.H, Element.H]
structure_alternative = Structure(coords, elements)

# Another variation on construction: can specify custom masses and/or charges
custom_masses = [1.001, 0.999]
custom_charges = [0.9, 1.1]
structure_custom = Structure(
    coords, elements=elements, masses=custom_masses, nuclear_charges=custom_charges
)

Loading a structure from file

A Structure object can also be loaded from a file. When loading from an XYZ file, coordinates are automatically converted from Angstrom to Bohr. When loading from a JSON file, coordinates are assumed to already be in Bohr.

  // Load a structure from an XYZ file (coordinates in Angstrom are converted to
  // Bohr)
  auto structure_from_file =
      Structure::from_xyz_file("../data/h2.structure.xyz");

  // Load a structure from a JSON file (coordinates are stored in Bohr)
  auto structure_from_json =
      Structure::from_json_file("../data/water.structure.json");
# Load a structure from an XYZ file (coordinates in Angstrom are converted to Bohr)
structure_from_file = Structure.from_xyz_file(
    Path(__file__).parent / "../data/h2.structure.xyz"
)

# Load a structure from a JSON file (coordinates are stored in Bohr)
structure_from_json = Structure.from_json_file(
    Path(__file__).parent / "../data/water.structure.json"
)

Accessing structure data

The Structure class provides methods to access atomic data:

Functions that deal with specific atoms include the word “atom” in their name (e.g., get_atom_coordinates), while functions that return properties for all atoms omit this word (e.g., get_coordinates). All atomic data is const and immutable once set, following QDK/Chemistry’s immutable data pattern. If you need to modify coordinates or other properties, you must create a new Structure object with the desired changes.

  // Get coordinates of a specific atom in Bohr
  Eigen::Vector3d atom_coords =
      structure.get_atom_coordinates(0);  // First atom

  // Get element of a specific atom
  Element element = structure.get_atom_element(0);  // First atom

  // Get all coordinates (in Bohr) as a matrix
  Eigen::MatrixXd all_coords = structure.get_coordinates();

  // Get all elements as a vector
  std::vector<Element> all_elements = structure.get_elements();
# Get coordinates of a specific atom
atom_coords = structure.get_atom_coordinates(0)  # First atom

# Get element of a specific atom
element = structure.get_atom_element(0)  # First atom

# Get all coordinates as a matrix
all_coords = structure.get_coordinates()

# Get all elements as a list
all_elements = structure.get_elements()

# Get nuclear repulsion energy
nuc_repulsion = structure.calculate_nuclear_repulsion_energy()

Serialization

The Structure class supports serialization to and from various formats. For detailed information about serialization in QDK/Chemistry, see the Serialization documentation.

Note

All structure-related files require the .structure suffix before the file type extension, for example molecule.structure.xyz and h2.structure.json for XYZ and JSON files respectively. This naming convention is enforced to maintain consistency across the QDK/Chemistry ecosystem.

File formats

As well as the JSON and HDF5 file formats supported for all data classes of QDK/Chemistry, there is the dedicated XYZ format for structures.

XYZ format

XYZ representation of a Structure:

2

H      0.000000    0.000000    0.000000
H      0.000000    0.000000    0.740848

Note that here the coordinates are in Angstrom, since this is the standard in xyz files.

Further reading

  • The above examples can be downloaded as complete C++ and Python scripts.

  • Serialization: Data serialization and deserialization