Commit 670a2c61 authored by Louis Beauloye's avatar Louis Beauloye
Browse files

[Ctypes] user models + enabling free memory with user models

parent c0f911d2
......@@ -707,6 +707,7 @@ MbsData* mbs_info_to_data(MbsInfos* mbs_infos, MbsData* s)
void mbs_delete_data(MbsData *s)
{
int i;
if (s->mbs_name)
......@@ -778,10 +779,10 @@ void mbs_delete_data(MbsData *s)
free_dvec_1(s->uxd);
free_dvec_1(s->ux0);
}
#ifndef SENSORKIN
// User models
if (s->Nuser_model)
if (s->Nuser_model && s->user_model != NULL)
{
mbs_delete_user_model(s->user_model);
}
......@@ -824,5 +825,5 @@ void mbs_delete_data(MbsData *s)
#endif
free(s);
}
......@@ -243,6 +243,9 @@ typedef struct MbsInfoParameter
int type; // scalar=1 ; vector=2 ; lut1D=3 ; lut2D=4 ; state=5 ; structure=6 : integer=7
int n_value;
double *value_list;
/** pointer to the memory storing the value in the UserModel structure (redundant with MbsInfoDData **d_value but simpler) **/
void* val_ptr;
MbsInfoDData **d_value; // d_data for the value
int is_symmmetric; // asymmetric = 0, symmetric master = 1, symmetric salve = 2
......@@ -255,9 +258,6 @@ typedef struct MbsInfoParameter
int flag_PRJPATH;
char* structure_lutfile;
/** pointer to the memory storing the value in the UserModel structure (redundant with MbsInfoDData **d_value but simpler) **/
void* val_ptr;
} MbsInfoParameter;
typedef struct MbsInfoUserModel
......
......@@ -45,6 +45,8 @@ class MbsInfoLink_c(ctypes.Structure):
pass
class MbsInfoUserModels_c(ctypes.Structure):
pass
class MbsInfoUserModel_c(ctypes.Structure):
pass
class MbsInfoUserIOs_c(ctypes.Structure):
pass
class MbsInfoParameter_c(ctypes.Structure):
......
......@@ -28,6 +28,7 @@ from .forward_decl import MbsInfoCuts_c
from .forward_decl import MbsInfoLinks_c
from .forward_decl import MbsInfoLink_c
from .forward_decl import MbsInfoUserModels_c
from .forward_decl import MbsInfoUserModel_c
from .forward_decl import MbsInfoUserIOs_c
from .forward_decl import MbsInfoPoint_c
from .forward_decl import MbsInfoSensor_c
......@@ -99,10 +100,29 @@ MbsInfoLinks_c._fields_ = [
#==============================================================================
MbsInfoLink_c._fields_ = [
("name", ctypes.c_char_p)
("name", ctypes.c_char_p),
#remaining fields not implemented
]
#==============================================================================
# MbsInfoUserModels_c
#==============================================================================
MbsInfoUserModels_c._fields_ = [
("n_user_model", ctypes.c_int),
("user_model_list", ctypes.POINTER(ctypes.POINTER(MbsInfoUserModel_c)))
]
#==============================================================================
# MbsInfoUserModel_c
#==============================================================================
MbsInfoUserModel_c._fields_ = [
("name", ctypes.c_char_p),
("n_parameter", ctypes.c_int),
("parameter_list", ctypes.POINTER(ctypes.POINTER(MbsInfoParameter_c)))
]
#==============================================================================
# MbsInfoPoint_c
#==============================================================================
......@@ -134,3 +154,15 @@ MbsInfoExtforce_c._fields_ = [
#remaining fields not implemented
]
#==============================================================================
# MbsInfoParameter_c
#==============================================================================
MbsInfoParameter_c._fields_ = [
("name", ctypes.c_char_p),
("type", ctypes.c_int),
("n_value", ctypes.c_int),
("value_list", ctypes.POINTER(ctypes.c_double)),
("val_ptr", ctypes.POINTER(ctypes.c_double))
#remaining fields not implemented
]
\ No newline at end of file
......@@ -52,7 +52,7 @@ from ..mbsysc_loader.callback import mbs_sensor_wrap
#==============================================================================
# Global parameter of the current module
#==============================================================================
__DEBUG__ = False
__DEBUG__ = True
__MODULE_DIR__ = os.path.dirname(os.path.abspath(__file__))
......@@ -223,6 +223,10 @@ class MbsData(object):
fixed frame) applied to each body.
tsim : scalar
The time value.
user_model : dict
Dictionary containing the names of the user models as keys and a second
dictionary with their parameters as values. The second dictionary
contains the names of the parameters as keys and their values as values
ux : ndarray
Numpy array containing the values of the user variables.
ux0 : ndarray
......@@ -385,6 +389,10 @@ class MbsData(object):
self.sensor_id = {}
self.__generate_id__()
#UserModel
self.user_model = _StrictDict()
self.__load_user_model__()
# Loading user function
if __DEBUG__ : print( "DEBUG>> Loading user functions")
......@@ -634,6 +642,11 @@ class MbsData(object):
The other symbolic function will be assigned when a module is
instancied.
Assign and wrap python user functions in which the arguments are not
dependent of another module instance (ie. MbsPart, MbsDirdyn...).
Store the functions in the MbsData instance
and assign the pointer of functions in the C structure
The functions will be assigned to the MbsData instance when
the 'run' function in other modules is called and unassigned
at the end.
......@@ -696,10 +709,6 @@ class MbsData(object):
__Q = np.ctypeslib.as_array(Q, (self.njoint+1,))
fun(self, tsim, __Q)
# def callback_undefined(self,function_name=None):
# print("undefined functions: "+function_name)
# return
def __unassign_user_fct__(self):
"""
Unassign all user function if all args are in MbsData instance.
......@@ -762,6 +771,37 @@ class MbsData(object):
index = self.mbs_infos_ptr.contents.extforce_point_list[i]
name = self.mbs_infos_ptr.contents.point_list[index].contents.extforce.contents.name.decode('utf-8')
self.extforce_id[name] = i+1
def __load_user_model__(self):
self.user_model._locked = False
infos_c_ptr=self.mbs_infos_ptr.contents
for i in range(infos_c_ptr.user_models.contents.n_user_model):
user_model_list = infos_c_ptr.user_models.contents.user_model_list[i].contents
name = user_model_list.name.decode('utf-8')
self.user_model[name] = _StrictDict()
self.user_model[name]._parent_key = name
self.user_model[name]._locked = False
self.user_model[name]._type = dict()
for j in range(user_model_list.n_parameter):
parameter_list = user_model_list.parameter_list[j].contents
name2 = parameter_list.name.decode('utf-8')
val_ptr = parameter_list.val_ptr
value_list = parameter_list.value_list
self.user_model[name]._type[name2] = parameter_list.type
size = parameter_list.n_value
UmPy = (ctypes.cast(val_ptr, ctypes.c_void_p).value==ctypes.cast(value_list, ctypes.c_void_p).value)
if UmPy :
self.user_model[name][name2] = np.ctypeslib.as_array(val_ptr, (1,size))
else :
#not yet tested, it requires user and symbolic fonctions in C
if self.user_model[name]._type[name2] == 5 or self.user_model[name]._type[name2] == 7:
self.user_model[name][name2] = np.ctypeslib.as_array(ctypes.cast(val_ptr, ctypes.POINTER(ctypes.c_int)), (1,size))
else :
self.user_model[name][name2] = np.ctypeslib.as_array(val_ptr, (1,size))
self.user_model[name]._locked = True
self.user_model._locked = True
......@@ -932,10 +972,7 @@ class MbsData(object):
mbs_part = MbsPart(self)
mbs_part.set_options(**kwargs)
mbs_part.run()
#==========================================================================
# Defining properties
#==========================================================================
......@@ -1166,3 +1203,72 @@ class MbsData(object):
@property
def mbs_name(self):
return ctypes.string_at(self.mbs_data_ptr.contents.mbs_name).decode("utf-8")
class _StrictDict(dict):
def __init__(self, *args, **kwargs):
dict.__init__(self, *args, **kwargs)
self._locked = True
self._parent_key = None
self._type = None
def __setitem__(self, key, value):
if self._locked == True:
if not (self._type is None):
if self._type[key] == 1:
if type(value) is float:
tab = self.__getarray__(key)
tab[0][0] = value
elif type(value) is int:
tab = self.__getarray__(key)
tab[0][0] = int(value)
else :
print("UserModel "+self._parent_key+"."+key+" is a float, "+str(type(value))+" was given")
elif self._type[key] == 7:
if type(value) is int:
tab = self.__getarray__(key)
tab[0][0] = value
else :
print("UserModel "+self._parent_key+"."+key+" is an int, "+str(type(value))+" was given")
elif self._type[key] == 2 or self._type[key] == 5:
if type(value) is np.ndarray or type(value) is list:
tab = self.__getarray__(key)
if np.size(value) == np.size(tab):
tab[:] = value[:]
else:
print("UserModel "+self._parent_key+"."+key+" is an array of size "+str(np.size(tab))+", array of size "+str(np.size(value))+" was given")
else :
print("UserModel "+self._parent_key+"."+key+" is an array, "+str(type(value))+" was given")
elif self._type[key] == 3:
print("Type lut1D for a user mode is not available in python")
elif self._type[key] == 4:
print("Type lut2D for a user mode is not available in python")
elif self._type[key] == 6:
print("Type structure for a user model is not available in python")
else :
print("Invalid type for the user model")
else :
dict.__setitem__(self, key, value)
def __getarray__(self, key):
return dict.__getitem__(self, key)
def __getitem__(self, key):
if self._type is None:
return dict.__getitem__(self, key)
else :
if self._type[key] == 1 or self._type[key] == 7 :
return dict.__getitem__(self, key)[0][0]
else:
return dict.__getitem__(self, key)[0]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment