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 Crystal
s:
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.BondingRule
— Typebonding_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 rulespecies_j::Symbol
: The other atom type for this bond rulemax_dist
: The maximum distance between the atoms for bonding to occur
Xtals.add_bonding_rules
— Functionadd_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
Xtals.read_bonding_rules
— Functionread_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
Xtals.write_bonding_rules
— Functionwrite_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 filebonding_rules::Array{BondingRule}
: (Optional) The rules to write to file. If not specified, the global rules are written.
Xtals.infer_bonds!
— Functioninfer_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. Settrue
to annotate all edges in thebonds
graph with vector information.sanity_check::Bool
: Optional. Setfalse
to skip the sanity check after inferring bonds.
Xtals.infer_bonds
— Functionbonds = infer_bonds(atoms; bonding_rules=rc[:bonding_rules])
Returns a MetaGraph
encoding the chemical bonds between atoms.
Arguments
atoms::Atoms{Cart}
: the atoms to bondbonding_rules::Vector{BondingRule}
: the bonding rules to use
Xtals.remove_bonds!
— Functionremove_bonds!(crystal)
Remove all bonds from a crystal structure, crystal::Crystal
.
Xtals.write_bond_information
— Functionwrite_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 filefilename::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 crystalbond_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.
Xtals.bond_distance
— Function`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).
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.
Xtals.clear_vectors!
— Function`clear_vectors!(xtal)`
`clear_vectors!(xtal.bonds)`
Removes edge vector attributes from crystal bonding graph.
Xtals.get_bond_vector
— Function`get_bond_vector(bonds, i, j)`
Returns the vector between connected nodes i
and j
of the bonds
graph.
Xtals.bond_angle
— Function`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