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.


featomic_status_t featomic_basic_systems_read(const char *path, struct featomic_system_t **systems, uintptr_t *count)

Read all structures in the file at the given path using chemfiles, and convert them to an array of featomic_system_t.

This function can read all formats supported by chemfiles.

This function allocates memory, which must be released using featomic_basic_systems_free.

If you need more control over the system behavior, consider writing your own instance of featomic_system_t.

Parameters:
  • path – path of the file to read from in the local filesystem

  • systems*systems will be set to a pointer to the first element of the array of featomic_system_t

  • count*count will be set to the number of systems read from the file

Returns:

The status code of this operation. If the status is not FEATOMIC_SUCCESS, you can use featomic_last_error() to get the full error message.

featomic_status_t featomic_basic_systems_free(struct featomic_system_t *systems, uintptr_t count)

Release memory allocated by featomic_basic_systems_read.

This function is only valid to call with a pointer to systems obtained from featomic_basic_systems_read, and the corresponding count. Any other use will probably result in segmentation faults or double free. If systems is NULL, this function does nothing.

Parameters:
  • systems – pointer to the first element of the array of featomic_system_t

  • count – number of systems in the array

Returns:

The status code of this operation. If the status is not FEATOMIC_SUCCESS, you can use featomic_last_error() to get the full error message.