SimObject — A class loads everything you need from C shared library¶
-
class
yourcode.YourSimObject¶ To load your C shared library, define a class inheriting
railgun.SimObject. You need to define four attribute:_clibname_,_clibdir_,_cmembers_and_cfuncs_.Note
In this document,
yourcode.YourSimObjectmeans the class you need to define. This class is not in RailGun.Example:
class YourSimObject(SimObject): _clibname_ = 'name_of_shared_library.so' _clibdir_ = 'path/to/shared/library' _cmembers_ = [ 'num_i', 'num_j', 'int scalar', 'int vector[i]', 'int matrix[i][j]', ... ] _cfuncs_ = [ 'name_of_c_function', ... ] def __init__(self, num_i, num_j, **kwds): SimObject.__init__(self, num_i=num_i, num_j=num_j, **kwds) def some_function(self, ...): ...
- You can override
railgun.SimObject.__init__(). - You can define additional python methods or members.
But be careful with name:
railgun.SimObjectwill overwrite the methods or members of your class with name in_cmembers_and_cfuncs_.
-
_clibname_¶ Name of your C shared library.
-
_clibdir_¶ Path to the directory where your C library locates. If you want to specify relative path from where this python module file are, you can use
relpath().
-
_cmembers_¶ This is a list of the definitions of C variables with the following syntax:
[CDT] VAR_NAME[INDEX] [= DEFAULT]
- VAR_NAME: name of variable
This let you access the C variable by obj.VAR_NAME.
Starting the name of the member with
num_defines an index whose name is what comes after this. For example,num_idefines indexi. Value ofnum_iis the size of array(s) along the indexi. For the member namednum_*, you can omit CDT (int).- CDT: C Data Type, (optional if VAR_NAME starts with
num_) - Choose CDT from the list in Relationships between C Data Type (CDT), numpy dtype and ctypes.
- INDEX: index, optional
If the variable is an array, INDEX should be specified. For an array with shape
num_i1 x num_i2 x ... x num_iN, INDEX should be[i1][i2]...[iN]or[i1,i2,...,iN].[i1][i2]...[iN]: multidimensional array- You can access
a[i][j]asself->a[i][j]in C code. This array data structure is called “Iliffe vector” or “display”. Strictly speaking, this is not equivalent to multidimensional array, but you can use as if it is. [i1,i2,...,iN]: flattened array- You can access
a[i][j]asself->a[i * self->num_j + j]in C code. Specifying correct index in C code is up to you. It is recommended to use macro or inline function.
- DEFAULT: a number, optional
- A default number for the variable. If VAR_NAME is an array, it will be filled with this value when it is created.
Warning
The order and number of the variables in
_cmembers_must be the same as in the C struct.Example:
_cmembers_ = [ 'num_i', 'num_j', 'num_k', 'int int_scalar', 'int int_vector1[i]', 'int int_vector2[j] = 0', 'int int_matrix[i][j]', 'double double_scalar = 0.1', 'double double_vector[k] = 18.2', 'double double_matrix[k][i] = -4.1', ]
See also:
railgun.cmems()
-
_cfuncs_¶ This is a list of the definitions of C functions with the following syntax:
[RETURN_VAR] FUNC_NAME(ARG, [ARG[, ...]])
- FUNC_NAME: string
Name of C function to be loaded. You don’t need to write the name of the struct. The name of the struct will be automatically prepended.
See also: Loading several C functions at once: func_{key|c1,c2}-notation (choices).
- RETURN_VAR: string, optional
- Name from C struct members. If specified, python wrapper function named FUNC_NAME returns value of RETURN_VAR.
- ARG:
Argument of C function, specified by the following syntax:
CDT_OR_INDEX ARG_NAME [= DEFAULT]
- CDT_OR_INDEX: string
- C Data Type or index.
If index
i(i<) is used here, error will be rasied if the argument x does not satisfy 0 <= x < num_i (0 < x <= num_i). - ARG_NAME: string
- Name of the argument.
- DEFAULT: a number or member of C struct, optional
- Default value for the argument.
You don’t need to write
selfwhich will be automatically passed as the first argument of C function.
Example:
_cfuncs_ = [ "func_spam()", "bar func_foo()", "func_with_args(int a, double b, i start=0, i< end=num_i)", "func_{key | c1, c2, c3}()", ]
See also: Constraints on C functions
-
_cstructname_¶ This is optional. This is used to specify the name of C struct explicitly:
class CStructName(SimObject): # 'CStructName' is name of c-struct ... class OtherNameForPyClass(SimObject): ... _cstructname_ = 'CStructName' # this is name of c-struct
-
_cfuncprefix_¶ This is optional. This is used to specify the prefix of C functions explicitly (default is name of C Struct +
_):class YourSimObject(SimObject): ... _cfuncprefix_ = 'MyPrefix' _cfuncs_ = [ "FuncName()", # 'MyPrefixFuncName' will be loaded ... ] class YourSimObject(SimObject): ... _cfuncprefix_ = '' _cfuncs_ = [ "FuncName()", # 'FuncName' will be loaded ... ]
-
_cmemsubsets_¶ dict of dict of list, optional.
It defines the subset of C functions and struct variables to be accessible. It must be of the following format:
{'<SUBSET_KEY_1>': { 'funcs': ['<FUNCTION_1>', '<FUNCTION_2>', ...], 'members': ['<MEMBER_1>', '<MEMBER_2>', ...], 'default': True, # optional (default is False) }, '<SUBSET_KEY_2>': {...}, ...}
This is useful when some subset of functions needs some subset of struct members. For example, when in “debugging mode”, you may want to record all temporal variables. However, allocating temporal variables can be wasteful if you are not debugging. Using
_cmemsubsets_, you can allocate temporal variables when in the debugging mode and make sure that the functions that requires temporal variables are callable only in the debugging mode. It helps you to avoid segmentation fault due to accessing invalid pointer._cmemsubsets_can be thought as machinery for “access levels”.- SUBSET_KEY : string
- You can pass boolean argument named
_cmemsubsets_SUBSET_KEYtorailgun.SimObject.__init__()to enable or disable the corresponding subset. - FUNCTION : list of strings
- These functions are accessible from Python when the corresponding
subset is enabled.
You can use short-hand notation
'func_{a, b, c}'to specify functions'func_a','func_b'and'func_c'. - MEMBER : list of strings
- These struct members are allocated and accessible from Python when the corresponding subset is enabled.
- DEFAULT : bool, optional
- It is False when not specified, meaning that the C members in this subset is not accessible.
Here is an example:
class YourSimObject(SimObject): _cmembers_ = [ # ... 'temp[j][k]', ] _cfuncs_ = [ 'run_{ mode | normal, debug }()', ] _cmemsubsets_ = { 'debug': { 'funcs': ['run_debug'], 'members': ['temp'], }, } # Run simulation in debugging mode: sim = YourSimObject(..., _cmemsubsets_debug=True) sim.run(mode='debug')
-
_cwrap_C_FUNC_NAME(func)¶ This is optional. If you want to wrap C function
C_FUNC_NAME, define this wrapper function.Example:
class YourSimObject(SimObject): _clibname_ = '...' _clibdir_ = '...' _cmembers_ = [ 'num_i', 'int vec[i]', ] _cfuncs_ = [ 'your_c_function', ] def _cwrap_your_c_function(old_c_function): def your_c_function(self, *args, **kwds): old_c_function(self, *args, **kwds) return self.vec[:] # return copy return your_c_function
After your_c_function is loaded from C library, your wrapper function will be called like this:
your_c_function = _cwrap_your_c_function(your_c_function)
-
_cerrors_¶ This is optional. When C function returns non-zero value, RailGun raises error which just tells the value returned (error code). To make the error message readable, or to handle the error better, you may want to use this attribute.
If C function returns the non-zero value
error_code, and it is found_cerrors_, RailGun will raise the error_cerrors_[error_code].Examples:
class YourSimObject(SimObject): _clibname_ = '...' _clibdir_ = '...' _cmembers_ = [...] _cfuncs_ = [...] class YourExceptionClass(Exception): pass _cerrors_ = { # set exception 1: RuntimeError('error code 1 is raised'), # you can use your own exception class 2: YourExceptionClass('your error message'), }
New in version 0.1.7.
- You can override
-
class
railgun.SimObject¶ -
setv(**kwds)¶ This is used for setting values of C struct members or any other Python attributes.
The following two lines have same effects:
obj.setv(scalar=1, array=[1, 2, 3]) obj.scalar = 1; obj.array = [1, 2, 3]
You can use alias for elements of array. The following lines have same effect:
obj.setv(var_0_1=1) obj.var[0][1] = 1
-
getv(*args)¶ Get the C variable by specifying the name or any other Python attributes.
The following lines have same effect:
var = obj.var var = obj.getv('var')
This is useful when you want to load multiple variables to local variable at once. The Following lines have same effect:
(a, b, c) = (obj.a, obj.b, obj.c) (a, b, c) = obj.getv('a', 'b', 'c') (a, c, c) = obj.getv('a, b, c')
-
num(*args)¶ Get the size along index. The Following lines have same effect:
num_i = obj.num_i num_i = obj.num('i')
You can specify multiple indices. The Following lines have same effect:
(num_i, num_j, num_k) = (obj.num_i, obj.num_j, obj.num_k) (num_i, num_j, num_k) = obj.num('i', 'j', 'k') (num_i, num_j, num_k) = obj.num('i, j, k')
-
Relationships between C Data Type (CDT), numpy dtype and ctypes¶
To specify C-language type of C struct members and C function arguments, the following C Data Types (CDTs) are available.
| CDT | C-language type | numpy dtype | ctypes |
|---|---|---|---|
char |
char |
character | c_char |
short |
short |
short | c_short |
ushort |
unsigned short |
ushort | c_ushort |
int |
int |
int32 | c_int |
uint |
unsigned int |
uint32 | c_uint |
long |
long |
int32 or int64 | c_long |
ulong |
unsigned long |
uint32 or uint64 | c_ulong |
longlong |
long long |
longlong | c_longlong |
ulonglong |
unsigned long long |
ulonglong | c_ulonglong |
float |
float |
float32 | c_float |
double |
double |
float | c_double |
longdouble |
long double |
longdouble | c_longdouble |
bool |
bool |
bool | c_bool |
Note
Numpy dtypes corresponding to CDTs long and ulong are chosen
based on the variable returned by platform.architecture().