xnn.ffnn.common.frc#

The MolSSI/SEAMM .frc force-field file format.

This is the one parameter-file format the ffnn family reads. It is the format of the SEAMM force-field distribution (molssi-seamm/forcefield_step, forcefield_step/data), a descendant of the Biosym .frc files, and it is force-field agnostic: OPLS-AA, ReaxFF, PCFF, Dreiding and the Buckingham potentials of battery materials all ship in it. What makes it worth adopting wholesale is that a file carries not only parameters but the typing rules: a #templates section of SMARTS patterns that assign the file’s own atom types to any structure (see xnn.ffnn.common.typing).

Grammar#

A file opens with a !MolSSI forcefield 1 line: the word after ! names the file’s dialect (MolSSI today, BIOSYM in the Biosym-era files the format descends from), and the trailing number is the format version, that is the version of the file grammar, not of the parameters inside. The current and only published format version is 1, which is what this module implements and writes (FRC_FORMAT_VERSION); a file declaring a newer number is still parsed, with a warning. Parameter versions live elsewhere: in the Version column of every data row and #define row (a date or a dotted number), and the reader always keeps the newest one per key. Everything else is organised in sections that start at a line beginning with # and run to the next such line:

#<kind> <label>            e.g.  #quadratic_bond oplsaa

Inside a section, ! lines are comments (the last one before the data is the column header), > lines are annotations (the energy expression), @ lines are modifiers (@units K2 kJ/mol/nm^2, @type rmin-eps, @combination geometric), and every other line is a data row:

Version     Ref   <atom-type key columns>   <value columns>
2023.01.29  1     opls_18   opls_18        1.5290   268.00

Special sections: #define <name> lists, per functional form, which labelled sections make up the force-field variant <name> (a file may define several variants, so oplsaa.frc defines oplsaa, CL&P and oplsaa+); #include <file> [missing_ok] splices another file in; #templates <label> and #fragments <label> hold JSON; #reference <n> holds free-text provenance; #end closes a section and is otherwise ignored.

Resolution#

FrcFile.forcefield() turns a #define into a ForceField: for every functional form, the newest row of the define (or the newest not above a requested version) names the labels to use, in order; the labelled sections are merged in that order so a later label overrides an earlier one for the same key (this is how CL&P extends oplsaa), and within a section the newest version of each key wins. A label ending in :optional may be absent. The result offers the bonded-parameter lookups force-field codes need – direct key, then the type’s equivalences, then the wildcard patterns in SEAMM’s precedence order – and the merged templates.

The reader is schema driven: SECTION_SCHEMA records, per section kind, how many leading columns form the atom-type key, the key’s symmetry (like_bond: i <= j; like_angle: i <= k; like_torsion; like_improper: central atom third), and the value columns with their default units, so @units modifiers are honoured. Kinds without a schema are read from their header line. New force fields register their sections with register_section_schema().

Module Attributes

FRC_FORMAT_VERSION

The .frc format version this module reads and writes (the trailing number of the !MolSSI forcefield 1 header).

Functions

builtin_data_dir()

Directory of the .frc files shipped with xnn.

canonical_key(symmetry, atoms)

Order an atom-type key canonically under a symmetry.

convert_units(value, src, dst)

Convert value from unit src to unit dst.

find_forcefield(spec[, include_dirs])

Resolve a force-field spec to (file, variant).

list_forcefields([include_dirs])

Every force-field variant available by name.

make_section(kind, label, key_columns, ...)

Build a Section from (key_tuple, values_dict) rows.

nonbond_to_sigma_eps(form, v1, v2[, unit1, ...])

Convert a nonbond row to (sigma [Å], epsilon [kcal/mol]).

parse_header(line)

Split a !<dialect> <kind> <version> header line.

parse_version(text)

Comparable form of a version token such as 2023.01.29 or 1.0.

read_forcefield(spec[, version, include_dirs])

Resolve a spec (see find_forcefield()) straight to a ForceField.

read_frc(path[, include_dirs])

Parse a .frc file (and its includes) into a FrcFile.

register_section_schema(kind, n_atoms, ...)

Register (or replace) the schema of a section kind.

unit_factor(src, dst)

Multiplicative factor taking src units to dst units.

write_frc(frc, path)

Write a FrcFile to disk in .frc syntax.

Classes

Define(name[, entries, source])

A #define <name> section: which labelled sections form a variant.

ForceField(name, file, version)

One resolved force-field variant: merged sections plus lookups.

FrcFile(path[, include_dirs])

A parsed .frc file (plus everything it #includes).

Reference(number, text[, author, date, source])

A #reference <n> block.

Row(version, reference, key, values[, source])

One data row of a parameter section.

Section(kind, label[, comments, ...])

A #<kind> <label> section.