TOP/ITP and FNC in RMC_POT

This page describes the functionality implemented by the following two classes.

  • RmcPotDatTop: Creates and edits GROMACS-style *.top and *.itp files for RMC_POT.

  • RmcPotDatFnc: Creates and edits Fixed Neighbour Constraint (*.fnc) files for RMC_POT.

TOP and FNC are not the same thing.

  • TOP/ITP describes molecular topology, bonds, angles, dihedrals, 1–4 pairs, explicit exclusions, virtual sites, and related information.

  • FNC specifies fixed-neighbour constraints that keep distances between final RMC atom indices within prescribed ranges.

In RMC_POT, ordinary FNC (fnc=1/2/3) and flexible molecules using TOP (fnc=4) are distinct features. Ordinary FNC and flexible molecules are not used simultaneously.


1. RmcPotDatTop

1.1 Supported TOP sections

RmcPotDatTop handles the following sections recognized by RMC_POT.

[ moleculetype ]
[ atoms ]
[ pairs ]
[ bonds ]
[ angles ]
[ dihedrals ]
[ exclusions ]
[ virtual_sites2 ]
[ virtual_sites3 ]
[ virtual_sites4 ]
[ system ]
[ molecules ]

It also handles preprocessor directives recognized by RMC_POT.

#include
#ifdef
#ifndef
#else
#endif

1.2 Reading and writing files

from rmc_pot_dat_top import RmcPotDatTop


top = RmcPotDatTop("sample", auto_write=False)

If the extension is omitted, the name becomes sample.top. An existing file is loaded during initialization.

The main file operations are as follows.

Method

Function

path

Returns the current TOP/ITP path.

load()

Loads an existing TOP/ITP file.

write()

Validates and writes the current contents.

write(out_name)

Writes to a different filename.

clear()

Clears all stored contents.

write() calls validate() before saving.

1.3 Automatic saving

With auto_write=True, changes are written after each setter or addition method.

top = RmcPotDatTop("sample", auto_write=True)
top.add_comment("comment")

When creating multiple entries together, use auto_write=False to avoid saving intermediate states.

top = RmcPotDatTop("sample", auto_write=False)
top.add_comment("comment", auto_write=False)
top.set_system("sample system", auto_write=False)
top.write()

1.4 Low-level line and section operations

Low-level methods are available for assembling TOP files directly.

Method

Function

add_raw_line(line)

Adds an arbitrary line outside sections.

add_comment(comment)

Adds a comment line beginning with ;.

add_section(name)

Adds a new section.

add_section_line(section_name, line)

Adds an arbitrary line to a specified section.

get_sections()

Returns all sections.

get_sections(name)

Returns sections with the specified name.

get_last_section(name)

Returns the last section with the specified name.

remove_sections(name)

Removes all sections with the specified name.

Use add_section_line() to preserve TOP lines that cannot be expressed using the dedicated methods.

1.5 Includes and conditional directives

top.add_include("molecule.itp", auto_write=False)
top.add_ifdef("_DEUTERIUM", auto_write=False)
top.add_raw_line("; deuterium definition", auto_write=False)
top.add_else(auto_write=False)
top.add_raw_line("; hydrogen definition", auto_write=False)
top.add_endif(auto_write=False)

The corresponding methods are as follows.

Method

Output

add_include(filename)

#include "filename"

add_ifdef(symbol)

#ifdef symbol

add_ifndef(symbol)

#ifndef symbol

add_else()

#else

add_endif()

#endif

validate() checks matching #ifdef/#ifndef and #endif directives, as well as the position of #else.


2. Molecular types and atoms in TOP

2.1 [ moleculetype ]

top.begin_molecule_type(
    name="SnI4",
    exclusions=3,
    auto_write=False,
)

exclusions corresponds to GROMACS nrexcl. An RMC_POT-specific index_offset may also be specified when necessary.

top.begin_molecule_type(
    name="MOL2",
    exclusions=3,
    index_offset=5000,
    auto_write=False,
)

2.2 [ atoms ]

top.add_atom(
    serial=1,
    atom_type="Sn",
    residue_number=1,
    residue_name="SnI4",
    atom_name="Sn",
    charge_group=1,
    charge=0.0,
    mass=None,
    first_rmc_index=1,
    second_rmc_index=2,
    auto_write=False,
)

The line generated by this method has the following format.

serial type resnr residue atom cgnr charge [mass] ; first_rmc_index second_rmc_index

The two values after the semicolon are specific to RMC_POT.

  • first_rmc_index: RMC index of this local atom in the first molecule of the same molecular type.

  • second_rmc_index: RMC index of this local atom in the second molecule of the same molecular type.

These are not molecule numbers. For each local atom, they record the RMC atom indices corresponding to the first and second molecular instances.

Example index mapping for SnI4

In the first SnI4 representation in the RMC_POT manual, the mapping is as follows.

Local atom

First molecule

Second molecule

Sn

1

2

I1

1001

1005

I2

1002

1006

I3

1003

1007

I4

1004

1008

The corresponding [ atoms ] entries are written as follows.

1 Sn 1 SnI4 Sn 1 0 ; 1 2
2 I  1 SnI4 I1 1 0 ; 1001 1005
3 I  1 SnI4 I2 1 0 ; 1002 1006
4 I  1 SnI4 I3 1 0 ; 1003 1007
5 I  1 SnI4 I4 1 0 ; 1004 1008

2.3 Virtual atoms

top.add_virtual_atom(
    serial=4,
    atom_type="VS",
    residue_number=1,
    residue_name="MOL",
    atom_name="VS",
    charge_group=1,
    charge=-1.0,
    mass=0.0,
    auto_write=False,
)

add_virtual_atom() adds an entry to [ atoms ] with RMC indices 0 0. This indicates a virtual site rather than a real atom to RMC_POT.


3. Interactions in TOP

The atom numbers below are GROMACS local atom numbers within one molecule, not RMC atom indices.

3.1 [ pairs ]

top.add_pair(
    atom_i=1,
    atom_j=4,
    function_type=1,
    auto_write=False,
)

V/W parameters can also be specified explicitly when required by the force field.

top.add_pair(
    atom_i=1,
    atom_j=4,
    function_type=1,
    v_parameter=V_VALUE,
    w_parameter=W_VALUE,
    auto_write=False,
)

v_parameter and w_parameter must either both be specified or both be omitted.

3.2 [ bonds ]

top.add_bond(
    atom_i=1,
    atom_j=2,
    equilibrium_nm=B0_NM,
    force_constant=KB,
    sigma=SIGMA_BOND,
    auto_write=False,
)
  • equilibrium_nm: Equilibrium bond distance in nm.

  • force_constant: Force constant of the harmonic bond potential.

  • sigma: RMC_POT weight, specified at the first occurrence of the required bond type.

Replace B0_NM, KB, and SIGMA_BOND with values from the chosen force field or independently determined RMC_POT parameters. This class does not estimate these values.

To place RMC-specific parameters after the semicolon, specify the following.

rmc_parameters_after_semicolon=True

3.3 [ angles ]

top.add_angle(
    atom_i=1,
    atom_j=2,
    atom_k=3,
    equilibrium_degree=THETA0_DEG,
    force_constant=KA,
    sigma=SIGMA_ANGLE,
    auto_write=False,
)

The central atom is atom_j.

3.4 Periodic dihedrals

top.add_periodic_dihedral(
    atom_i=1,
    atom_j=2,
    atom_k=3,
    atom_l=4,
    equilibrium_degree=PHI0_DEG,
    force_constant=KPHI,
    multiplicity=N,
    sigma=SIGMA_DIHEDRAL,
    auto_write=False,
)

3.5 Harmonic dihedrals

top.add_harmonic_dihedral(
    atom_i=1,
    atom_j=2,
    atom_k=3,
    atom_l=4,
    equilibrium_degree=XI0_DEG,
    force_constant=KXI,
    sigma=SIGMA_DIHEDRAL,
    auto_write=False,
)

3.6 Ryckaert–Bellemans dihedral

top.add_rb_dihedral(
    atom_i=1,
    atom_j=2,
    atom_k=3,
    atom_l=4,
    coefficients=[C0, C1, C2, C3, C4, C5],
    sigma=SIGMA_DIHEDRAL,
    auto_write=False,
)

coefficients must contain exactly six values.

3.7 Explicit exclusions

top.add_exclusion(
    centre_atom=1,
    excluded_atoms=[2, 3, 4],
    auto_write=False,
)

Adds a central atom and its excluded partners to [ exclusions ].


4. Virtual sites

4.1 Virtual sites defined by two atoms

top.add_virtual_site2(
    site=4,
    atom_i=1,
    atom_j=2,
    a=A,
    host_atom=1,
    auto_write=False,
)

4.2 Virtual sites defined by three atoms

top.add_virtual_site3(
    site=5,
    atom_i=1,
    atom_j=2,
    atom_k=3,
    function_type=1,
    parameters=[A, B],
    host_atom=1,
    auto_write=False,
)

The required number of parameters depends on function_type.

Function type

RMC_POT category

Parameters

1

3

a, b

2

3fd

a, d_nm

3

3fad

theta_degree, d_nm

4

3out

a, b, c_nm_inverse

4.3 Virtual sites defined by four atoms

top.add_virtual_site4(
    site=6,
    atom_i=1,
    atom_j=2,
    atom_k=3,
    atom_l=4,
    a=A,
    b=B,
    c_nm=C_NM,
    host_atom=1,
    auto_write=False,
)

5. [ system ] and [ molecules ]

top.set_system("SnI4 index mapping example", auto_write=False)
top.set_molecules([
    ("SnI4", 2),
], auto_write=False)

set_system() and set_molecules() replace existing sections with the same names.

Molecule names in [ molecules ] must already be defined in [ moleculetype ].


6. High-level TOP generation methods

6.1 add_molecule_template()

Use this when multiple molecules of the same type exist and their RMC atom indices follow a regular pattern.

atoms = [
    {
        "serial": 1,
        "atom_type": "Sn",
        "residue_name": "SnI4",
        "atom_name": "Sn",
        "charge": 0.0,
        "mass": None,
    },
    {
        "serial": 2,
        "atom_type": "I",
        "residue_name": "SnI4",
        "atom_name": "I1",
        "charge": 0.0,
        "mass": None,
    },
    {
        "serial": 3,
        "atom_type": "I",
        "residue_name": "SnI4",
        "atom_name": "I2",
        "charge": 0.0,
        "mass": None,
    },
    {
        "serial": 4,
        "atom_type": "I",
        "residue_name": "SnI4",
        "atom_name": "I3",
        "charge": 0.0,
        "mass": None,
    },
    {
        "serial": 5,
        "atom_type": "I",
        "residue_name": "SnI4",
        "atom_name": "I4",
        "charge": 0.0,
        "mass": None,
    },
]

first_instance_indices = {
    1: 1,
    2: 1001,
    3: 1002,
    4: 1003,
    5: 1004,
}

second_instance_indices = {
    1: 2,
    2: 1005,
    3: 1006,
    4: 1007,
    5: 1008,
}

top.add_molecule_template(
    molecule_name="SnI4",
    atoms=atoms,
    first_instance_indices=first_instance_indices,
    second_instance_indices=second_instance_indices,
    exclusions=3,
    auto_write=False,
)

This example only demonstrates how to specify index mappings; it does not establish the validity of bond, charge, or nonbonded parameters.

first_instance_indices and second_instance_indices

Each dictionary maps a local atom number within a molecule to its RMC atom index.

local serial -> RMC atom index

Each dictionary contains the complete mapping for all local atoms in the first or second molecular instance, respectively.

Entries that can be added together

add_molecule_template() accepts the following arguments.

  • atoms

  • pairs

  • bonds

  • angles

  • periodic_dihedrals

  • harmonic_dihedrals

  • rb_dihedrals

  • explicit_exclusions

Each interaction entry is a keyword-argument dictionary passed to the corresponding low-level method.

bonds = [
    {
        "atom_i": 1,
        "atom_j": 2,
        "equilibrium_nm": B0_NM,
        "force_constant": KB,
        "sigma": SIGMA_BOND,
    },
]

6.2 validate_rmc_index_progression()

Checks whether the index difference between the first and second instances remains constant for the third and subsequent instances.

RmcPotDatTop.validate_rmc_index_progression(
    first_instance=first_instance_indices,
    second_instance=second_instance_indices,
    all_instances=[
        first_instance_indices,
        second_instance_indices,
        third_instance_indices,
    ],
)

The following relation is checked for each local atom.

index in instance n
= first index + (n - 1) * (second index - first index)

If the mapping does not satisfy this condition, add_molecule_template() cannot enable RMC_POT to reconstruct the indices of subsequent molecules unambiguously.

6.3 add_explicit_network_molecule()

This method enumerates an irregular continuous network as a single topology unit covering the entire cell.

top.add_explicit_network_molecule(
    molecule_name="NETWORK",
    atoms=atoms,
    exclusions=2,
    bonds=bonds,
    angles=angles,
    auto_write=False,
)

Each atoms entry may specify its final RMC index using rmc_index.

{
    "serial": 1,
    "rmc_index": 1,
    "atom_type": "Si",
    "residue_name": "NETWORK",
    "atom_name": "Si1",
    "charge": 0.0,
    "mass": None,
}

If rmc_index is omitted, serial is used.

This method automatically sets the following values.

first_rmc_index  = rmc_index
second_rmc_index = rmc_index
[ system ]       = molecule_name
[ molecules ]    = molecule_name 1

This approach explicitly specifies all atoms in the cell and all required bonds, angles, and dihedrals. It does not arbitrarily split a continuous network, such as SiO2 glass, into independent small molecules.


7. TOP validation

validate() primarily checks the following.

  • Proper matching of conditional preprocessor directives.

  • Number and format of lines in [ moleculetype ].

  • That [ atoms ] follows [ moleculetype ].

  • Presence of first and second RMC indices in [ atoms ].

  • Duplicate local serial numbers within a molecule.

  • That bonds, angles, dihedrals, etc. refer to existing local serial numbers.

  • Absence of duplicate [ system ] sections.

  • That molecule names in [ molecules ] have been defined.

  • That molecule counts are at least one.

Validation checks TOP syntax and internal references, but not the physical validity of force-field parameters.


8. RmcPotDatFnc

8.1 Information stored in FNC

FNC stores two kinds of information.

  1. rmin–rmax for each constraint type.

  2. For each RMC atom index, the partner atom indices and their constraint types.

Atom numbers in FNC are not local molecular numbers. They are 1-based final RMC atom indices corresponding to the final *.cfg file.

8.2 Initialization

from rmc_pot_dat_fnc import RmcPotDatFnc


fnc = RmcPotDatFnc(
    "sample",
    atom_count=TOTAL_ATOM_COUNT,
    auto_write=False,
)

atom_count is the total number of atoms in the RMC structure. Initialization creates an empty neighbour list for every atom from 1 through atom_count.

To load an existing FNC file, specify only its filename.

fnc = RmcPotDatFnc("existing.fnc", auto_write=False)

8.3 File operations

Method

Function

path

Returns the current FNC path.

initialize(atom_count)

Resets all internal state.

load()

Loads an existing FNC file.

write()

Validates and writes the FNC file.

write(out_name)

Writes to a different filename.

set_title(title)

Sets the header title.

get_title()

Returns the title.

get_atom_count()

Returns the total number of atoms.


9. FNC distance-constraint types

9.1 Setting one type at a time

fnc.set_distance_range(
    constraint_type=1,
    rmin=RMIN_1,
    rmax=RMAX_1,
    auto_write=False,
)

constraint_type values are added consecutively, starting at 1.

9.2 Setting multiple types at once

Dictionary form:

fnc.set_distance_ranges(
    {
        1: (RMIN_1, RMAX_1),
        2: (RMIN_2, RMAX_2),
    },
    auto_write=False,
)

List form:

fnc.set_distance_ranges(
    [
        (RMIN_1, RMAX_1),
        (RMIN_2, RMAX_2),
    ],
    auto_write=False,
)

The first list element corresponds to constraint type 1, and the second to type 2.

Retrieval:

ranges = fnc.get_distance_ranges()

This class does not infer distance ranges from structures or element names. Specify rmin and rmax explicitly based on the system being studied.


10. Operations on FNC atom pairs

10.1 Adding one reciprocal pair

fnc.add_pair(
    atom_index1=ATOM_I,
    atom_index2=ATOM_J,
    constraint_type=1,
    auto_write=False,
)

add_pair() registers both directions simultaneously.

ATOM_I -> ATOM_J
ATOM_J -> ATOM_I

10.2 Adding multiple pairs at once

fnc.add_pairs(
    [
        (ATOM_I, ATOM_J, 1),
        (ATOM_K, ATOM_L, 2),
    ],
    auto_write=False,
)

Each tuple has the following order.

(atom_index1, atom_index2, constraint_type)

10.3 Adding a one-way neighbour entry

fnc.add_neighbour(
    atom_index=ATOM_I,
    neighbour_index=ATOM_J,
    constraint_type=1,
    reciprocal=False,
    auto_write=False,
)

Use add_pair() for ordinary reciprocal FNC pairs. add_neighbour() is a low-level operation.

Setting reciprocal=True registers both directions.

10.4 Replacing the neighbour list of one atom

fnc.set_atom_neighbours(
    atom_index=ATOM_I,
    neighbours=[
        (ATOM_J, 1),
        (ATOM_K, 2),
    ],
    auto_write=False,
)

Each entry has the following format.

(neighbour_atom_index, constraint_type)

This method replaces only the list belonging to the specified atom. It does not automatically update the partner atoms. Prefer add_pair() or add_pairs() when reciprocal registration is required.

Retrieval:

neighbours = fnc.get_atom_neighbours(ATOM_I)

The return value is a list of FncNeighbour objects.

10.5 Removing a pair

fnc.remove_pair(
    ATOM_I,
    ATOM_J,
    reciprocal=True,
    auto_write=False,
)

With reciprocal=True, the pair is removed in both directions.

10.6 Removing all pairs for one atom

fnc.clear_atom_neighbours(
    ATOM_I,
    reciprocal=True,
    auto_write=False,
)

With reciprocal=True, reverse references stored by partner atoms are also removed.


11. Expanding FNC templates

11.1 Expanding one instance

Expands local molecular pairs into actual RMC atom indices.

local_pairs = [
    (1, 2, 1),
    (1, 3, 1),
]

local_to_rmc = {
    1: RMC_INDEX_1,
    2: RMC_INDEX_2,
    3: RMC_INDEX_3,
}

fnc.add_template_instance(
    local_pairs=local_pairs,
    local_to_rmc=local_to_rmc,
    auto_write=False,
)

local_pairs has the following format.

(local_atom_1, local_atom_2, constraint_type)

local_to_rmc defines the following mapping.

local atom serial -> final RMC atom index

This method does not generate pairs from element names, coordinates, or distances. It only maps the supplied local pairs to the supplied RMC indices.

11.2 Expanding multiple instances

fnc.add_template_instances(
    local_pairs=local_pairs,
    instances=[
        {
            1: RMC_INDEX_A1,
            2: RMC_INDEX_A2,
            3: RMC_INDEX_A3,
        },
        {
            1: RMC_INDEX_B1,
            2: RMC_INDEX_B2,
            3: RMC_INDEX_B3,
        },
    ],
    auto_write=False,
)

Unlike TOP’s first_instance_indices/second_instance_indices, FNC’s add_template_instances() requires explicit mappings for every instance. This is because the FNC file directly stores final RMC indices for all atoms.


12. Complete-graph FNC constraints

fnc.add_group_complete_graph(
    atom_indices=[ATOM_1, ATOM_2, ATOM_3, ATOM_4],
    constraint_type=1,
    auto_write=False,
)

Registers every possible pair within the specified group as an FNC pair.

For four atoms, the following six pairs are added.

1-2
1-3
1-4
2-3
2-4
3-4

This does not simply connect a central atom to surrounding atoms. It constrains every atom pair within the group, so use it only where appropriate.


13. FNC validation and retrieval

13.1 validate()

fnc.validate()

Reciprocal registration is also checked by default.

The main checks are as follows.

  • atom_count is at least 1.

  • Constraint types are consecutive, starting at 1.

  • Atom entries exist for all indices from 1 through atom_count.

  • Partner atom indices are within range.

  • Constraint types are defined.

  • No duplicate neighbour entries exist for the same atom.

  • Each FNC pair is registered in the reverse direction with the same type.

Use the following only when validating special one-way data.

fnc.validate(require_reciprocal=False)

13.2 Retrieving the pair list

pairs = fnc.as_pairs(unique=True)

With unique=True, each reciprocally registered pair is returned only once.

(i, j, constraint_type)

To retrieve both directions:

pairs = fnc.as_pairs(unique=False)

14. Basic procedure for creating an FNC file

Replace the example distance ranges and atom indices with values appropriate to the target structure.

from rmc_pot_dat_fnc import RmcPotDatFnc


fnc = RmcPotDatFnc(
    "sample",
    atom_count=TOTAL_ATOM_COUNT,
    auto_write=False,
)

fnc.set_title("Fixed neighbours constraints (.FNC) file", auto_write=False)

fnc.set_distance_ranges(
    [
        (RMIN_1, RMAX_1),
        (RMIN_2, RMAX_2),
    ],
    auto_write=False,
)

fnc.add_pairs(
    [
        (ATOM_I, ATOM_J, 1),
        (ATOM_K, ATOM_L, 2),
    ],
    auto_write=False,
)

fnc.validate()
fnc.write()

15. Choosing between TOP and FNC

Purpose

Use

Ordinary FNC to keep atom-pair distances within specified ranges

RmcPotDatFnc

Generate *.fnc for fnc=1/2/3

RmcPotDatFnc

Bond, angle, and dihedral potentials for flexible molecules

RmcPotDatTop

Specify molecular topology with fnc=4

RmcPotDatTop

GROMACS-style topology for nonbonded potentials

RmcPotDatTop

1–4 pairs, exclusions, and virtual sites

RmcPotDatTop

Handle multiple identical molecules with regular index arrangements

add_molecule_template()

Enumerate an irregular network covering the entire cell as one unit

add_explicit_network_molecule()

Expand the same local FNC pairs to multiple instances

add_template_instances()

It is important not to confuse ordinary FNC with flexible molecules defined through TOP.


16. Implementation notes

TOP

  • Atom numbers in add_bond() and similar methods are local serial numbers within a molecule.

  • Only the first and second indices at the end of [ atoms ] are RMC atom indices.

  • Bond lengths, force constants, charges, and sigma values are not determined automatically.

  • validate() checks syntax and referential consistency, not the physical validity of parameters.

  • Use add_molecule_template() only when RMC index arrangements follow a regular pattern.

  • Do not assume nonexistent small-molecule templates for irregular networks.

FNC

  • All atom numbers are final RMC atom indices.

  • set_atom_neighbours() does not automatically create reverse references.

  • Use add_pair()/add_pairs() for ordinary reciprocal pairs.

  • add_group_complete_graph() constrains every atom pair within the group.

  • Distance ranges and pairs are not inferred automatically.

  • Validation, including reciprocal-registration checks, is performed before write().