# Topology¶

class `Topology`

A topology contains the definition of all the atoms in the system, as well as the liaisons between the particles (bonds, angles, dihedrals, …) and the residues.

Only the atoms and the bonds are stored, the angles, dihedrals and impropers are automaticaly deduced from the bonds.

It is also possible to iterate over a `Topology`, yielding all the atoms in the system.

```auto topology = Topology();

for (Atom& atom: topology) {
assert(atom.name() == "Fe");
}
```

Public Functions

`Topology`()

Construct a new empty topology

```auto topology = Topology();

assert(topology.size() == 0);
assert(topology.bonds().size() == 0);
```

Atom &`operator[]`(size_t index)

Get a reference to the atom at the position `index`.

```auto topology = Topology();

assert(topology[0].name() == "Co");
assert(topology[1].name() == "V");

topology[2].set_mass(45);
assert(topology[2].mass() == 45);
```

Parameters
• `index`: the atomic index

Exceptions
• `OutOfBounds`: if `index` is greater than `size()`

const Atom &`operator[]`(size_t index) const

Get a const reference to the atom at the position `index`.

```auto topology = Topology();

assert(topology[0].name() == "Co");
assert(topology[1].name() == "V");

topology[2].set_mass(45);
assert(topology[2].mass() == 45);
```

Parameters
• `index`: the atomic index

Exceptions
• `OutOfBounds`: if `index` is greater than `size()`

void `add_atom`(Atom atom)

Add an `atom` at the end of this topology.

```auto topology = Topology();

assert(topology.size() == 1);
assert(topology[0].name() == "Zn");
```

Parameters
• `atom`: the new atom to add

void `remove`(size_t i)

Delete the atom at index `i` in this topology, as well as all the bonds involving this atom.

This function modify the index of all the atoms after `i`, and modify the bond list accordingly.

```auto topology = Topology();
assert(topology.size() == 3);

assert(topology[1].name() == "Fe");
topology.remove(0);

// atomic indexes are shifted by remove
assert(topology[1].name() == "Rd");
```

Parameters
• `i`: the index of the atom to remove

Exceptions
• `OutOfBounds`: if `i` is greater than size()

void `add_bond`(size_t atom_i, size_t atom_j, Bond::BondOrder bond_order = Bond::UNKNOWN)

Add a bond in the system, between the atoms at index `atom_i` and `atom_j`.

```auto topology = Topology();

assert(topology.bonds() == std::vector<Bond>({{0, 1}, {1, 2}}));
// angles are automaticaly computed too
assert(topology.angles() == std::vector<Angle>({{0, 1, 2}}));
```

Parameters
• `atom_i`: the index of the first atom in the bond

• `atom_j`: the index of the second atom in the bond

• `bond_order`: the bond order for the bond added

Exceptions
• `OutOfBounds`: if `atom_i` or `atom_j` are greater than `size()`

• `Error`: if `atom_i == atom_j`, as this is an invalid bond

void `remove_bond`(size_t atom_i, size_t atom_j)

Remove a bond in the system, between the atoms at index `atom_i` and `atom_j`.

If the bond does not exist, this does nothing.

```auto topology = Topology();

assert(topology.bonds() == std::vector<Bond>({{0, 1}, {1, 2}}));

topology.remove_bond(1, 0);
assert(topology.bonds() == std::vector<Bond>({{1, 2}}));

// This does nothing
topology.remove_bond(0, 2);
assert(topology.bonds() == std::vector<Bond>({{1, 2}}));
```

Parameters
• `atom_i`: the index of the first atom in the bond

• `atom_j`: the index of the second atom in the bond

Exceptions
• `OutOfBounds`: if `atom_i` or `atom_j` are greater than `size()`

Bond::BondOrder `bond_order`(size_t atom_i, size_t atom_j) const

Get the bond order for the given bond

If the bond does not exist, this will thrown an Error.

```auto topology = Topology();

// Lookup by the bond index
assert(topology.bond_orders()[0] == Bond::SINGLE);
assert(topology.bond_orders()[1] == Bond::SINGLE);
assert(topology.bond_orders()[2] == Bond::DOUBLE);

// Lookup by the atom indexes
assert(topology.bond_order(0, 1) == Bond::SINGLE);
assert(topology.bond_order(3, 4) == Bond::DOUBLE);
```

Parameters
• `atom_i`: the index of the first atom in the bond

• `atom_j`: the index of the second atom in the bond

Exceptions
• `OutOfBounds`: if `atom_i` or `atom_j` are greater than `size()`

• `Error`: if no bond between `atom_i` and `atom_j` exists.

size_t `size`() const

Get the number of atoms in the topology

```auto topology = Topology();
assert(topology.size() == 0);

topology.resize(22);
assert(topology.size() == 22);

assert(topology.size() == 23);
```

void `resize`(size_t size)

Resize the topology to hold `size` atoms, adding new atoms as needed.

If the new number of atoms is bigger than the old one, pre-existing atoms are conserved.

If the new size if smaller than the old one, all atoms and connectivity elements after the new size are removed.

```auto topology = Topology();
assert(topology.size() == 0);

topology.resize(22);
assert(topology.size() == 22);
```

Parameters
• `size`: the new size of the topology

void `reserve`(size_t size)

Allocate memory in the frame to be able to store data for `size` atoms.

This function does not change the actual number of atoms in the topology, and should be used as an optimisation.

```auto topology = Topology();
assert(topology.size() == 0);

topology.resize(10);
assert(topology.size() == 10);

// reserve allocate memory, but does not change the size
topology.reserve(100);
assert(topology.size() == 10);
```

Parameters
• `size`: the number of elements to reserve memory for

const std::vector<Bond> &`bonds`() const

Get the bonds in the system

The bonds are sorted according to `operator<(const Bond&, const Bond&)`, which mean it is possible to look for a bond in the list using a binary search (`std::lower_bound`).

```auto topology = Topology();

assert(topology.bonds() == std::vector<Bond>({{0, 1}, {1, 2}}));

auto bonds = topology.bonds();
// perform a binary search in the bonds
auto it = std::lower_bound(bonds.begin(), bonds.end(), Bond(1, 2));
assert(it != bonds.end());
assert(*it == Bond(1, 2));
```

const std::vector<Bond::BondOrder> &`bond_orders`() const

Get the bond orders in the system.

The bond orders are sorted so that the index of each bond is the same as its index in the array returned by `Topology::bonds`. This means that the bond order for `Topology::bonds()[index]` would be given by `bond_orders()[index]`.

```auto topology = Topology();

// Lookup by the bond index
assert(topology.bond_orders()[0] == Bond::SINGLE);
assert(topology.bond_orders()[1] == Bond::SINGLE);
assert(topology.bond_orders()[2] == Bond::DOUBLE);

// Lookup by the atom indexes
assert(topology.bond_order(0, 1) == Bond::SINGLE);
assert(topology.bond_order(3, 4) == Bond::DOUBLE);
```

const std::vector<Angle> &`angles`() const

Get the angles in the system

The angles are sorted according to `operator<(const Angle&, const Angle&)`, which mean it is possible to look for an angle in the list using a binary search (`std::lower_bound`).

```auto topology = Topology();

assert(topology.angles() == std::vector<Angle>({{0, 1, 2}, {1, 2, 3}}));

auto angles = topology.angles();
// perform a binary search in the angles
auto it = std::lower_bound(angles.begin(), angles.end(), Angle(1, 2, 3));
assert(it != angles.end());
assert(*it == Angle(1, 2, 3));
```

const std::vector<Dihedral> &`dihedrals`() const

Get the dihedral angles in the system

The dihedrals are sorted according to `operator<(const Dihedral&, const Dihedral&)`, which mean it is possible to look for a dihedral in the list using a binary search (`std::lower_bound`).

```auto topology = Topology();

assert(topology.dihedrals() == std::vector<Dihedral>({{0, 1, 2, 3}}));

auto dihedrals = topology.dihedrals();
// perform a binary search in the dihedrals
auto it = std::lower_bound(
dihedrals.begin(), dihedrals.end(), Dihedral(0, 1, 2, 3)
);
assert(it != dihedrals.end());
assert(*it == Dihedral(0, 1, 2, 3));
```

const std::vector<Improper> &`impropers`() const

Get the improper dihedral angles in the system

The impropers are sorted according to `operator<(const Improper&, const Improper&)`, which mean it is possible to look for an improper in the list using a binary search (`std::lower_bound`).

```auto topology = Topology();

assert(topology.impropers() == std::vector<Improper>({{1, 0, 2, 3}}));

auto impropers = topology.impropers();
// perform a binary search in the impropers
auto it = std::lower_bound(
impropers.begin(), impropers.end(), Improper(1, 0, 2, 3)
);
assert(it != impropers.end());
assert(*it == Improper(1, 0, 2, 3));
```

void `clear_bonds`()

Remove all bonding information in the topology (bonds, angles and dihedrals)

```auto topology = Topology();

assert(topology.bonds().size() == 2);
assert(topology.angles().size() == 1);

topology.clear_bonds();
assert(topology.bonds().size() == 0);
assert(topology.angles().size() == 0);
```

void `add_residue`(Residue residue)

Add a `residue` to this topology.

```auto topology = Topology();

assert(topology.residues().size() == 0);

auto residue = Residue("first");

assert(topology.residues().size() == 1);
```

Parameters
• `residue`: the residue to add to this topology

Exceptions
• `chemfiles::Error`: if any atom in the `residue` is already in another residue in this topology. In that case, the topology is not modified.

bool `are_linked`(const Residue &first, const Residue &second) const

Check if two residues are linked together, i.e. if there is a bond between one atom in the `first` residue and one atom in the `second` one. Both residues should be in this topology.

The two residues are the same (`first == second`), this function returns `true`.

```auto topology = Topology();

auto first = Residue("first");

auto second = Residue("second");

```

optional<const Residue&> `residue_for_atom`(size_t index) const

Get the residue containing the atom at the given `index`.

If no residue contains this atom, this function returns `nullopt`.

```auto topology = Topology();

auto first = Residue("first");

assert(topology.residue_for_atom(0));
assert(topology.residue_for_atom(0)->name() == "first");

assert(!topology.residue_for_atom(1));
assert(topology.residue_for_atom(1) == nullopt);
```

const Residue &`residue`(size_t index) const

Get the residue at the given `index` in this topology

There is no guarantee that this index matches the residue id.

```auto topology = Topology();

auto first = Residue("first");

assert(topology.residue(0).name() == "first");
```

const std::vector<Residue> &`residues`() const

Get all the residues in the topology as a vector

```auto topology = Topology();

auto residues = topology.residues();
assert(residues.size() == 2);
assert(residues[0].name() == "first");
assert(residues[1].name() == "second");
```

# Connectivity elements¶

class `Bond`

The `Bond` class ensure a canonical representation of a bond two atoms.

This class implements all the comparison operators, as well as indexing.

```auto bond = Bond(55, 23);

// indexing
assert(bond[0] == 23);
assert(bond[1] == 55);

// equality
assert(bond == Bond(23, 55));
assert(bond != Bond(23, 24));

// lexicographic comparison
assert(bond < Bond(44, 55));
assert(bond >= Bond(12, 33));
```

Public Types

enum `BondOrder`

Stores the type of bond.

Values:

`UNKNOWN` = 0

Bond order is unknown or unspecified.

`SINGLE` = 1

Single bond.

`DOUBLE` = 2

Double bond.

`TRIPLE` = 3

Triple bond.

`QUADRUPLE` = 4

`QINTUPLET` = 5

Quintuplet bond.

`DOWN` = 250

Single bond direction from frist atom to second is ‘down’. Used for cis-trans isomers.

`UP` = 251

Single bond direction from first atom to second is ‘up’. Used for cis-trans isomers.

`DATIVE_R` = 252

Dative bond where the electrons are localized to the first atom.

`DATIVE_L` = 253

Dative bond where the electrons are localized to the second atom.

`AMIDE` = 254

Amide bond (C(=O)-NH)

`AROMATIC` = 255

Aromatic bond (for example the ring bonds in benzene)

Public Functions

`Bond`(size_t i, size_t j)

Create a new `Bond` containing the atoms `i` and `j`.

Exceptions
• `Error`: if `i == j`

size_t `operator[]`(size_t i) const

Get the index of the `i`th atom (`i == 0` or `i == 1`) in the bond.

Exceptions
• `OutOfBounds`: if `i` is not 0 or 1

class `Angle`

The `Angle` class ensure a canonical representation of an angle between three atoms.

An angle is formed by two consecutive bonds:

```|  i       k  |
|    \   /    |
|      j      |
```

This class implements all the comparison operators, as well as indexing.

```auto angle = Angle(55, 23, 12);

// indexing
assert(angle[0] == 12);
assert(angle[1] == 23);
assert(angle[2] == 55);

// equality
assert(angle == Angle(12, 23, 55));
assert(angle != Angle(12, 23, 24));

// lexicographic comparison
assert(angle < Angle(44, 23, 55));
assert(angle >= Angle(11, 33, 14));
```

Public Functions

`Angle`(size_t i, size_t j, size_t k)

Create a new `Angle` containing the atoms `i`, `j` and `k`.

Exceptions
• `Error`: if `i == j`, `j == k` or `i == k`

size_t `operator[]`(size_t i) const

Get the index of the `i`th atom (`i == 0`, `i == 1` or `i == 2`) in the angle.

Exceptions
• `OutOfBounds`: if `i` is not 0, 1 or 2

class `Dihedral`

The `Dihedral` class ensure a canonical representation of a dihedral angle between four atoms.

A dihedral angle is formed by three consecutive bonds:

```|  i       k     |
|    \   /   \   |
|      j      m  |
```

This class implements all the comparison operators, as well as indexing.

```auto dihedral = Dihedral(2, 55, 23, 12);

// indexing
assert(dihedral[0] == 12);
assert(dihedral[1] == 23);
assert(dihedral[2] == 55);
assert(dihedral[3] == 2);

// equality
assert(dihedral == Dihedral(12, 23, 55, 2));
assert(dihedral != Dihedral(12, 23, 24, 2));

// lexicographic comparison
assert(dihedral < Dihedral(44, 23, 55, 1));
assert(dihedral >= Dihedral(11, 33, 14, 4));
```

Public Functions

`Dihedral`(size_t i, size_t j, size_t k, size_t m)

Create a new `Dihedral` containing the atoms `i`, `j`, `k` and `m`.

Exceptions
• `Error`: if any of `i`, `j`, `k`, `m` has the same value as another

size_t `operator[]`(size_t i) const

Get the index of the `i`th atom (`i` can be 0, 1, 2 or 3) in the dihedral.

Exceptions
• `OutOfBounds`: if `i` is not 0, 1, 2 or 3.

class `Improper`

The `Improper` class ensure a canonical representation of an improper dihedral angle between four atoms.

An improper dihedral angle is formed by three bonds around a central atom:

```|  i       k  |
|    \   /    |
|      j      |
|      |      |
|      m      |
```

This class implements all the comparison operators, as well as indexing.

The second atom of the improper is always the central atom.

```auto improper = Improper(2, 55, 23, 12);

// indexing
assert(improper[0] == 2);
assert(improper[1] == 55);
assert(improper[2] == 12);
assert(improper[3] == 23);

// equality
assert(improper == Improper(12, 55, 2, 23));
assert(improper != Improper(12, 55, 2, 21));

// lexicographic comparison
assert(improper < Improper(44, 23, 55, 8));
assert(improper >= Improper(11, 33, 14, 1));
```

Public Functions

`Improper`(size_t i, size_t j, size_t k, size_t m)

Create a new `Improper` containing the atoms `i`, `j`, `k` and `m`. `j` must be the central atom of the improper.

Exceptions
• `Error`: if any of `i`, `j`, `k`, `m` has the same value as another

size_t `operator[]`(size_t i) const

Get the index of the `i`th atom (`i` can be 0, 1, 2 or 3) in the improper.

Exceptions
• `OutOfBounds`: if `i` is not 0, 1, 2 or 3.