Defining systems

There are two ways you can define systems to pass to featomic_calculator_compute(): the easy way is to use featomic_basic_systems_read() to read all systems defined in a file, and run the calculation on all these systems. The more complex but also more flexible way is to create a featomic_system_t manually, implementing all required functions; and then passing one or more systems to featomic_calculator_compute().

struct featomic_system_t

A featomic_system_t deals with the storage of atoms and related information, as well as the computation of neighbor lists.

This struct contains a manual implementation of a virtual table, allowing to implement the rust System trait in C and other languages. Speaking in Rust terms, user_data contains a pointer (analog to Box<Self>) to the struct implementing the System trait; and then there is one function pointers (Option<unsafe extern fn(XXX)>) for each function in the System trait.

The featomic_status_t return value for the function is used to communicate error messages. It should be 0/FEATOMIC_SUCCESS in case of success, any non-zero value in case of error. The error will be propagated to the top-level caller as a FEATOMIC_SYSTEM_ERROR

A new implementation of the System trait can then be created in any language supporting a C API (meaning any language for our purposes); by correctly setting user_data to the actual data storage, and setting all function pointers to the correct functions. For an example of code doing this, see the SystemBase class in the Python interface to featomic.

WARNING: all function implementations MUST be thread-safe, function taking const pointer parameters can be called from multiple threads at the same time. The featomic_system_t itself might be moved from one thread to another.

Public Members

void *user_data

User-provided data should be stored here, it will be passed as the first parameter to all function pointers below.

featomic_status_t (*size)(const void *user_data, uintptr_t *size)

This function should set *size to the number of atoms in this system

featomic_status_t (*types)(const void *user_data, const int32_t **types)

This function should set *types to a pointer to the first element of a contiguous array containing the atomic types of each atom in the system. Different atomic types should be identified with a different value. These values are usually the atomic number, but don’t have to be. The array should contain featomic_system_t::size() elements.

featomic_status_t (*positions)(const void *user_data, const double **positions)

This function should set *positions to a pointer to the first element of a contiguous array containing the atomic cartesian coordinates. positions[0], positions[1], positions[2] must contain the x, y, z cartesian coordinates of the first atom, and so on.

featomic_status_t (*cell)(const void *user_data, double *cell)

This function should write the unit cell matrix in cell, which have space for 9 values. The cell should be written in row major order, i.e. ax ay az bx by bz cx cy cz, where a/b/c are the unit cell vectors.

featomic_status_t (*compute_neighbors)(void *user_data, double cutoff)

This function should compute the neighbor list with the given cutoff, and store it for later access using pairs or pairs_containing.

featomic_status_t (*pairs)(const void *user_data, const struct featomic_pair_t **pairs, uintptr_t *count)

This function should set *pairs to a pointer to the first element of a contiguous array containing all pairs in this system; and *count to the size of the array/the number of pairs.

This list of pair should only contain each pair once (and not twice as i-j and j-i), should not contain self pairs (i-i); and should only contains pairs where the distance between atoms is actually bellow the cutoff passed in the last call to compute_neighbors. This function is only valid to call after a call to compute_neighbors.

featomic_status_t (*pairs_containing)(const void *user_data, uintptr_t atom, const struct featomic_pair_t **pairs, uintptr_t *count)

This function should set *pairs to a pointer to the first element of a contiguous array containing all pairs in this system containing the atom with index atom; and *count to the size of the array/the number of pairs.

The same restrictions on the list of pairs as featomic_system_t::pairs applies, with the additional condition that the pair i-j should be included both in the return of pairs_containing(i) and pairs_containing(j).

struct featomic_pair_t

Pair of atoms coming from a neighbor list

Public Members

uintptr_t first

index of the first atom in the pair

uintptr_t second

index of the second atom in the pair

double distance

distance between the two atoms

double vector[3]

vector from the first atom to the second atom, accounting for periodic boundary conditions. This should be position[second] - position[first] + H * cell_shift where H is the cell matrix.

int32_t cell_shift_indices[3]

How many cell shift where applied to the second atom to create this pair.