In this document we will specify the low-level interfaces of the comminity codes. These interfaces should follow a pattern. This pattern is described bellow. This pattern can be used to keep the interfaces of the codes consistent between codes of different physical domains and to help in learning about the functionality of the interfaces. In later chapters we define the specific interfaces for the modules of different physical domains. The actual interface of a code should derive from these interfaces.
These interfaces only specify the low-level interfaces. The low-level interfaces do not support unit handling, data conversion and attributes. This functionality is handled by the next-level interfaces described in nextlevel_.
The exact size (in bytes) and type of the values sent between the python layer and the community codes is very important. In this document we will specify the type of each argument and return value. Currently AMUSE supports 4 types, these are described in the following table.
All functions in the interface should follow the same template. Each function returns an error or status code. Results are returned through the function arguments. In C these arguments need to be pointers to valid memory locations.
Example template for the other functions defined in this specification. All functions should follow this example..
int32 example_function(int32 input, float64 * output, float64 * inout);
FUNCTION example_function(input, output, inout) INTEGER :: input DOUBLE PRECISION :: output, inout INTEGER :: example_function END FUNCTION
Function will return an error code.
The error codes all have the same general form. Zero stands for no error, a negative value indicates some error happened, a positive value is returned when the function ends in a special state.
Codes can have a number of parameters. Some parameters are domain specific, these parameters are found for all codes in a specific domain (for example the smoothing length in gravitational dynamics). Other parameters are only defined and used by a specific code. The domain specific parameters are defined on the domain specific interfaces, when a code supports the parameter it should implement the specified functions. Other parameters have to be accessed with functions following the template of the get_example_parameter() and set_example_parameter() functions.
Retrieve the current value of the parameter. Note, values can be any of the supported types.
int32 get_example_parameter(float64 * value);
FUNCTION get_example_parameter(value) DOUBLE PRECISION :: value INTEGER :: get_example_parameter END FUNCTION
|Parameters:||value (float64, OUT) – The current value of the parameter.|
Update the value of the parameter. The type of the new value argument must be the same as the get_example_parameter() function.
int32 set_example_parameter(float64 value);
FUNCTION set_example_parameter(value) DOUBLE PRECISION :: value INTEGER :: set_example_parameter END FUNCTION
|Parameters:||value (float64, IN) – The new value of the parameter.|
A function used to access (set or get) a parameter may only retrieve or update the value of a single parameter. Functions setting two or more parameters in one go are not supported by the next-level interfaces. After all parameters have been set, the initialize_code() function should be called, this gives the code the opportunity prepare the model.
Let the code perform initialization actions after all parameters have been set. Should be called once per running code instance.
FUNCTION initialize_code() INTEGER :: initialize_code END FUNCTION
Codes can work on particles or grids (stars, black holes or gas). The methods in the Object Management category define the functionality to create, remove and query the particles or gridpoints in the codes.
When a code supports objects, the code is responsible for managing these objects. The code needs to assign a unique index to a particle so that the particle can be referred to in other function calls. This is a major difference with the MUSE code. Where the user of the code was responsible for assigning unique ids to the particles. This change makes the implementation of the code simpler and allows the code to support creation of new objects during simulation. For example a hydrocode can add or delete gridpoints during the evolution of the model.
Particles in the same physical domain can have a well known, minimal state. For example, in the gravitational dynamics domain the state of a particle can be defined by a location vector, velocity vector, a mass and a radius. The methods in the Object State category provide a way to access this state in one function.
Not all information of a particle can be transfered with the get_state and set_state functions. Some codes may support other properties of a particle, the code can define get_ and set_ functions for these properties. These functions follow the pattern defined in the Parameters category. The functions must either get or set a scalar property (1 argument) or a vector property (3 arguments).
The main function of a code is often evolving a model in time or solving a steady state solution. The methods that control model evolution or start and stop the model calculations all belong to the Model evolution category. At this time, no pattern is defined for the functions in this category.
The state of the code can be queried, before, during and after the model calculations. All the functions in this category follow the ‘get_name’ pattern. The state of code should not change during a function call to a function in this category. The functions must either get a scalar property (1 argument) or a vector property (3 arguments).
Some codes can provide services for other codes in the same or other physical domains. For example, gravitational dynamics code might provide a function to calculate the gravity force at a point. The methods that provide these services all belong to this category.