Chemical Bonding

Chemical bonding interactions are represented in the bonds attribute of a Crystal as a graph. The nodes of the graph correspond to the Crystal's Atoms, and the edges of the graph correspond to the bonds (xtal.bonds).

Bonding Rules

Xtals uses an array of BondingRule structs stored in rc for deciding if two Atoms are an appropriate distance to be chemically bonded. The default rules are based on the Cordero covalent radii, modified based on the work of Thomas Manz. Each BondingRule is composed of two chemical species symbols and a floating point value, the maximum distance for inferring a bond between the indicated species.

BondingRule(:C, :C, 1.77)

The global bonding rules may be augmented with add_bonding_rules or written to/read from disk with write_bonding_rules and read_bonding_rules. The default rules are determined from rc[:covalent_radii] at module load, but are not recalculated upon changes to the covalent radii. If rc[:covalent_radii] is altered and new bonding rules should be calculated, the user must do rc[:bonding_rules] = bondingrules().

Adding Bonds to Crystals

By default, bonding information is not added to a Crystal. Bonds may be inferred at the time of loading structure data by using the infer_bonds keyword argument. See Crystal for more details.

xtal = Crystal("SBMOF-1.cif"; infer_bonds=true, periodic_boundaries=true)
xtal.bonds

# output

{120, 144} undirected Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)

The first number is the number of nodes, and the second is the number of edges. The :weight attribute is not used, and can be ignored.

remove_bonds! clears the bonding information from a Crystal:

remove_bonds!(xtal)
xtal.bonds

# output

{120, 0} undirected Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)

Use infer_bonds! to infer plausible bonds using the global bonding rules (or another specified set of rules) in already-loaded Crystals:

infer_bonds!(xtal, true)
xtal.bonds

# output

{120, 144} undirected Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)

Bonds from Input File

Some chemical information formats, like .cif and .mol, can store not only the cartesian coordinates of atoms, but also the graph of bonds between atoms in molecules and crystals. The read_bonds_from_file keyword argument for Crystal enables loading these bonds when reading the data. read_mol also returns bond information.

Bonds for Atoms

In the case that atomic coordinates are loaded from XYZ format, there will be no unit cell information. To infer bonds between atoms in this case, use the infer_bonds function:

atoms = Cart(xtal.atoms, xtal.box) # get atoms in Cartesian coords
bonds = infer_bonds(atoms) # infer bonding graph

# output

{120, 110} undirected Int64 metagraph with Float64 weights defined by :weight (default weight 1.0)

Bond Distances, Vectors, and Angles

Bonds may be labeled with several additional pieces of information. The first is the center-to-center distance between the bonded atoms, accessible via bond_distance:

bond_distance(xtal, 1, 5)

# output

1.5233240952030063

The bond distance is automatically added by infer_bonds!. Applying calculate_bond_vectors! (or passing calculate_vectors=true to infer_bonds!) labels each edge in the bonding graph with a vector, accessible via get_bond_vector:

calculate_bond_vectors!(xtal)
get_bond_vector(xtal, 1, 5)

# output

3-element Vector{Float64}:
 -1.2460713575602618
 -0.26441824999999985
  0.8354073616870523

While the bond graph itself is undirected, the vectors returned by get_bond_vector are directed, so reversing the order of the node indices will flip the vector:

get_bond_vector(xtal, 5, 1)

# output

3-element Vector{Float64}:
  1.2460713575602618
  0.26441824999999985
 -0.8354073616870523

Bond angles are calculated via the dot product: θ = arccos(u⃗•v⃗ / (‖u⃗‖*‖v⃗‖)) To get the angle (in radians) between two bonds, use bond_angle:

bond_angle(xtal, 1, 5, 9)

# output

2.089762039489374

Detailed Docs

Xtals.BondingRuleType
bonding_rule = BondingRule(:Ca, :O, 2.0)
bonding_rules = [BondingRule(:H, :*, 1.2),
                 BondingRule(:*, :*, 1.9)]

A rule for determining if two atoms within a crystal are bonded.

Attributes

  • species_i::Symbol: One of the atoms types for this bond rule
  • species_j::Symbol: The other atom type for this bond rule
  • max_dist: The maximum distance between the atoms for bonding to occur
source
Xtals.add_bonding_rulesFunction
add_bonding_rules(bonding_rules)

Adds bonding_rules to the beginning of the global bonding rules list

Arguments

  • bonding_rules::Array{BondingRule} : the array of bonding rules to add
source
Xtals.read_bonding_rulesFunction
read_bonding_rules("file.csv")

Reads a CSV file of bonding rules and returns a BondingRule array.

Arguments

  • filename::AbstractString : name of file in data directory containing bonding rules

Returns

rules::Array{BondingRule} : the bonding rules read from file

source
Xtals.write_bonding_rulesFunction
write_bonding_rules("file.csv")

Writes bonding rules to a CSV file that can be loaded with read_bonding_rules

Arguments

  • filename::AbstractString : The name of the output file
  • bonding_rules::Array{BondingRule} : (Optional) The rules to write to file. If not specified, the global rules are written.
source
Xtals.infer_bonds!Function
infer_bonds!(crystal, include_bonds_across_periodic_boundaries; bonding_rules=rc[:bonding_rules])

Populate the bonds in the crystal object based on the bonding rules. If a pair doesn't have a suitable rule then they will not be considered bonded.

:* is considered a wildcard and can be substituted for any species. It is a good idea to include a bonding rule between two :* to allow any atoms to bond as long as they are close enough.

The bonding rules are hierarchical, i.e. the first bonding rule takes precedence over the latter ones.

Arguments

  • crystal::Crystal: The crystal that bonds will be added to.
  • include_bonds_across_periodic_boundaries::Bool: Whether to check across the periodic boundary when calculating bonds.
  • bonding_rules::Array{BondingRule, 1}: The array of bonding rules that will be used to fill the bonding information. They are applied in the order that they appear. rc[:bonding_rules] will be used if none provided.
  • calculate_vectors::Bool: Optional. Set true to annotate all edges in the bonds graph with vector information.
  • sanity_check::Bool: Optional. Set false to skip the sanity check after inferring bonds.
source
Xtals.infer_bondsFunction
bonds = infer_bonds(atoms; bonding_rules=rc[:bonding_rules])

Returns a MetaGraph encoding the chemical bonds between atoms.

Arguments

  • atoms::Atoms{Cart}: the atoms to bond
  • bonding_rules::Vector{BondingRule}: the bonding rules to use
source
Xtals.write_bond_informationFunction
write_bond_information(crystal)
write_bond_information(crystal, filename)
write_bond_information(crystal, center_at_origin=false)
write_bond_information(xtal, filename, :cross_boundary => p -> p, "bonds.vtk") # cross-boundary bonds only
write_bond_information(xtal, filename, :distance => d -> d < 1.0, "bonds.vtk") # distance less than 1.0

Writes the bond information from a crystal to the selected filename.

Arguments

  • crystal::Crystal: The crystal to have its bonds written to a vtk file
  • filename::AbstractString: The filename the bond information will be saved to. If left out, will default to crystal name.
  • center_at_origin::Bool: (optional) center the coordinates at the origin of the crystal
  • bond_filter::Pair{Symbol, Function}: (optional) a key-value pair of an edge attribute and a predicate function. Bonds with attributes that cause the predicate to return false are excluded from writing.
  • verbose::Bool: (optional) if true, prints output file name to console.
source
Xtals.bond_distanceFunction
`bond_distance(xtal, i, j)`
`bond_distance(xtal.bonds, i, j)`

Gives the distance between two bonded atoms in a crystal or two nodes in a bonding graph. Returns NaN if the atoms (nodes) are not bonded (connected).

source
Xtals.calculate_bond_vectors!Function
`calculate_bond_vectors!(xtal)`

Adds a property to the edges of a crystal's bonding graph giving the vector between source and destination nodes in Cartesian space.

source
Xtals.clear_vectors!Function
`clear_vectors!(xtal)`
`clear_vectors!(xtal.bonds)`

Removes edge vector attributes from crystal bonding graph.

source
Xtals.get_bond_vectorFunction
`get_bond_vector(bonds, i, j)`

Returns the vector between connected nodes i and j of the bonds graph.

source
Xtals.bond_angleFunction
`bond_angle(xtal.bonds, 2, 1, 3)`
`bond_angle(xtal, 8, 121, 42)`

Returns the bond angle between three nodes of a bonding graph (or three atoms in a crystal), if the edges (bonds) exist. Otherwise, returns NaN

source