32 #include "structmember.h" 35 PyObject *modena_SurrogateModel = NULL;
37 void modena_substitute_model_calculate_maps
43 PyObject *pMaps = PyObject_CallMethod
45 parent->
pModel,
"calculate_maps",
"(O)", sm->model->
pModel 47 if(!pMaps){ Modena_PyErr_Print(); }
49 PyObject *pMapOutputs = PyTuple_GET_ITEM(pMaps, 0);
50 if(!pMapOutputs){ Modena_PyErr_Print(); }
51 PyObject *pSeq = PySequence_Fast(pMapOutputs,
"expected a sequence");
52 sm->map_outputs_size = PySequence_Size(pMapOutputs);
53 sm->map_outputs = malloc(sm->map_outputs_size*
sizeof(
double));
56 for(i = 0; i < sm->map_outputs_size; i++)
58 sm->map_outputs[i] = PyInt_AsSsize_t(PyList_GET_ITEM(pSeq, i));
60 sm->map_outputs_size /= 2;
62 Py_DECREF(pMapOutputs);
63 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
65 PyObject *pMapInputs = PyTuple_GET_ITEM(pMaps, 1);
66 if(!pMapInputs){ Modena_PyErr_Print(); }
67 pSeq = PySequence_Fast(pMapInputs,
"expected a sequence");
68 sm->map_inputs_size = PySequence_Size(pMapInputs);
69 sm->map_inputs = malloc(sm->map_inputs_size*
sizeof(
double));
70 for(i = 0; i < sm->map_inputs_size; i++)
72 sm->map_inputs[i] = PyInt_AsSsize_t(PyList_GET_ITEM(pSeq, i));
74 sm->map_inputs_size /= 2;
76 Py_DECREF(pMapInputs);
77 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
86 PyObject *pSubstituteModels = PyObject_GetAttrString
88 self->pModel,
"substituteModels" 90 if(!pSubstituteModels){ Modena_PyErr_Print(); }
92 PyObject *pSeq = PySequence_Fast
94 pSubstituteModels,
"expected a sequence" 96 self->substituteModels_size = PySequence_Size(pSubstituteModels);
97 self->substituteModels =
100 for(i = 0; i <
self->substituteModels_size; i++)
102 PyObject *args = PyTuple_New(0);
103 PyObject *kw = Py_BuildValue
105 "{s:O}",
"model", PyList_GET_ITEM(pSeq, i)
108 self->substituteModels[i].model = (
modena_model_t *) PyObject_Call
110 (PyObject *) &modena_model_tType,
117 if(!self->substituteModels[i].model)
121 PyErr_ExceptionMatches(modena_DoesNotExist)
122 || PyErr_ExceptionMatches(modena_ParametersNotValid)
126 PyObject_GetAttrString(PyList_GET_ITEM(pSeq, i),
"_id");
127 if(!pModelId){ Modena_PyErr_Print(); }
128 const char* modelId = PyString_AsString(pModelId);
131 PyObject *pRet = NULL;
134 PyErr_ExceptionMatches(modena_DoesNotExist)
140 "Loading model %s failed - Attempting automatic initialisation\n",
144 pRet = PyObject_CallMethod
146 modena_SurrogateModel,
157 "Parameters of model %s are invalid - Trying to initialise\n",
161 pRet = PyObject_CallMethod
163 modena_SurrogateModel,
164 "exceptionParametersNotValid",
170 if(!pRet){ Modena_PyErr_Print(); }
171 int ret = PyInt_AsLong(pRet);
174 modena_error_code = ret;
177 Py_DECREF(pSubstituteModels);
183 Modena_PyErr_Print();
188 self->substituteModels[i].inputs = modena_inputs_new
190 self->substituteModels[i].model
193 self->substituteModels[i].outputs = modena_outputs_new
195 self->substituteModels[i].model
198 modena_substitute_model_calculate_maps
200 &self->substituteModels[i],
206 Py_DECREF(pSubstituteModels);
207 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
212 void modena_model_get_minMax
217 PyObject *pObj = PyObject_CallMethod(self->pModel,
"minMax", NULL);
218 if(!pObj){ Modena_PyErr_Print(); }
220 PyObject *pMin = PyTuple_GET_ITEM(pObj, 0);
221 PyObject *pSeq = PySequence_Fast(pMin,
"expected a sequence");
222 self->inputs_internal_size = PySequence_Size(pSeq);
223 self->inputs_min = malloc(self->inputs_internal_size*
sizeof(
double));
225 for(i = 0; i <
self->inputs_internal_size; i++)
227 self->inputs_min[i] = PyFloat_AsDouble(PyList_GET_ITEM(pSeq, i));
230 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
232 PyObject *pMax = PyTuple_GET_ITEM(pObj, 1);
233 pSeq = PySequence_Fast(pMax,
"expected a sequence");
234 self->inputs_max = malloc(self->inputs_internal_size*
sizeof(
double));
235 for(i = 0; i <
self->inputs_internal_size; i++)
237 self->inputs_max[i] = PyFloat_AsDouble(PyList_GET_ITEM(pSeq, i));
240 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
242 PyObject *pinames = PyTuple_GET_ITEM(pObj, 2);
243 pSeq = PySequence_Fast(pinames,
"expected a sequence");
244 self->inputs_names = malloc(self->inputs_size*
sizeof(
char*));
245 for(i = 0; i <
self->inputs_size; i++)
247 self->inputs_names[i] =
248 strdup(PyString_AsString(PyList_GET_ITEM(pSeq, i)));
251 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
253 PyObject *ponames = PyTuple_GET_ITEM(pObj, 3);
254 pSeq = PySequence_Fast(ponames,
"expected a sequence");
255 self->outputs_size = PySequence_Size(pSeq);
256 self->outputs_names = malloc(self->outputs_size*
sizeof(
char*));
257 for(i = 0; i < PySequence_Size(pSeq); i++)
259 self->outputs_names[i] =
260 strdup(PyString_AsString(PyList_GET_ITEM(pSeq, i)));
263 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
265 PyObject *ppnames = PyTuple_GET_ITEM(pObj, 4);
266 pSeq = PySequence_Fast(ppnames,
"expected a sequence");
267 self->parameters_size = PySequence_Size(pSeq);
268 self->parameters_names = malloc(self->parameters_size*
sizeof(
char*));
269 for(i = 0; i < PySequence_Size(pSeq); i++)
271 self->parameters_names[i] =
272 strdup(PyString_AsString(PyList_GET_ITEM(pSeq, i)));
275 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
287 PyObject *args = PyTuple_New(0);
288 PyObject *kw = Py_BuildValue(
"{s:s}",
"modelId", modelId);
290 PyObject *pNewObj = PyObject_Call
292 (PyObject *) &modena_model_tType,
303 PyErr_ExceptionMatches(modena_DoesNotExist)
304 || PyErr_ExceptionMatches(modena_ParametersNotValid)
309 PyObject *pRet = NULL;
312 PyErr_ExceptionMatches(modena_DoesNotExist)
318 "Loading model %s failed - " 319 "Attempting automatic initialisation\n",
323 pRet = PyObject_CallMethod
325 modena_SurrogateModel,
336 "Parameters of model %s are invalid - " 337 "Trying to initialise\n",
341 pRet = PyObject_CallMethod
343 modena_SurrogateModel,
344 "exceptionParametersNotValid",
350 if(!pRet){ Modena_PyErr_Print(); }
351 int ret = PyInt_AsLong(pRet);
354 modena_error_code = ret;
359 Modena_PyErr_Print();
368 PyObject *pRet = PyObject_CallMethod
375 if(!pRet){ Modena_PyErr_Print(); }
376 size_t argPos = PyInt_AsSsize_t(pRet);
379 if(self->argPos_used)
386 self->argPos_used[argPos] =
true;
394 PyObject *pRet = PyObject_CallMethod
401 if(!pRet){ Modena_PyErr_Print(); }
402 size_t ret = PyInt_AsSsize_t(pRet);
413 for(j = 0; j <
self->inputs_internal_size; j++)
415 if(!self->argPos_used[j])
419 fprintf(stderr,
"argPos %zu not used", j);
427 fprintf(stderr,
"Not all input arguments used - Exiting\n");
434 return self->inputs_names;
439 return self->outputs_names;
444 return self->parameters_names;
449 return self->inputs_size;
454 return self->outputs_size;
459 return self->parameters_size;
462 int modena_substitute_model_call
470 for(j = 0; j < sm->map_inputs_size; j++)
481 sm->inputs->inputs[sm->map_inputs[2*j+1]] =
482 inputs->inputs[sm->map_inputs[2*j]];
486 if(ret){
return ret; }
488 for(j = 0; j < sm->map_outputs_size; j++)
499 inputs->inputs[sm->map_outputs[2*j+1]] =
500 sm->outputs->outputs[sm->map_outputs[2*j]];
506 int write_outside_point
512 PyObject* pOutside = PyList_New(self->inputs_internal_size);
515 for(j = 0; j <
self->inputs_internal_size; j++)
519 pOutside, j, PyFloat_FromDouble(inputs->inputs[j])
523 PyObject *pRet = PyObject_CallMethod
526 "exceptionOutOfBounds",
531 if(!pRet){ Modena_PyErr_Print(); }
532 int ret = PyInt_AsLong(pRet);
535 modena_error_code = ret;
561 self->parameters_size == 0
562 && self->parameters_size != self->mf->parameters_size
565 return write_outside_point(
self, inputs);
569 for(j = 0; j <
self->substituteModels_size; j++)
571 int ret = modena_substitute_model_call
573 &self->substituteModels[j],
577 if(ret){
return ret; }
580 for(j = 0; j <
self->inputs_internal_size; j++)
596 inputs->inputs[j] < self->inputs_min[j]
597 || inputs->inputs[j] > self->inputs_max[j]
600 return write_outside_point(
self, inputs);
625 self->parameters_size == 0
626 && self->parameters_size != self->mf->parameters_size
629 write_outside_point(
self, inputs);
633 for(j = 0; j <
self->substituteModels_size; j++)
635 modena_substitute_model_call
637 &self->substituteModels[j],
643 for(j = 0; j <
self->inputs_internal_size; j++)
668 for(i = 0; i <
self->substituteModels_size; i++)
670 Py_XDECREF(self->substituteModels[i].model);
671 modena_inputs_destroy(self->substituteModels[i].inputs);
672 modena_outputs_destroy(self->substituteModels[i].outputs);
673 free(self->substituteModels[i].map_inputs);
674 free(self->substituteModels[i].map_outputs);
676 free(self->substituteModels);
678 free(self->parameters);
679 free(self->inputs_min);
680 free(self->inputs_max);
682 free(self->argPos_used);
686 modena_function_destroy(self->mf);
689 for(i = 0; i <
self->inputs_size; i++)
691 free(self->inputs_names[i]);
693 free(self->inputs_names);
695 for(i = 0; i <
self->outputs_size; i++)
697 free(self->outputs_names[i]);
699 free(self->outputs_names);
701 for(i = 0; i <
self->parameters_size; i++)
703 free(self->parameters_names[i]);
705 free(self->parameters_names);
707 Py_XDECREF(self->pModel);
709 self->ob_type->tp_free((PyObject*)
self);
734 static PyMemberDef modena_model_t_members[] = {
735 {
"outputs_size", T_PYSSIZET,
737 {
"inputs_size", T_PYSSIZET,
739 {
"parameters_size", T_PYSSIZET,
748 static PyObject *modena_model_t_call
757 PyObject *pI=NULL, *pCheckBounds=NULL;
758 bool checkBounds =
true;
760 static char *kwlist[] = {
"inputs",
"checkBounds", NULL };
764 !PyArg_ParseTupleAndKeywords
775 Modena_PyErr_Print();
780 checkBounds = PyObject_IsTrue(pCheckBounds);
783 if(!PyList_Check(pI))
785 printf(
"First argument is not a list\n");
789 PyObject *pSeq = PySequence_Fast(pI,
"expected a sequence");
790 size_t len = PySequence_Size(pI);
792 if(len != self->inputs_internal_size)
795 printf(
"input array has incorrect size %zu %zu\n", len, self->inputs_internal_size);
802 for(j = 0; j < len; j++)
806 inputs, j, PyFloat_AsDouble(PyList_GET_ITEM(pSeq, j))
810 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
818 modena_inputs_destroy(inputs);
819 modena_outputs_destroy(outputs);
824 "Surrogate model is used out-of-bounds" 835 PyObject* pOutputs = PyList_New(self->outputs_size);
836 for(j = 0; j <
self->outputs_size; j++)
840 pOutputs, j, PyFloat_FromDouble(modena_outputs_get(outputs, j))
843 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
845 modena_inputs_destroy(inputs);
846 modena_outputs_destroy(outputs);
864 static PyMethodDef modena_model_t_methods[] = {
865 {
"call", (PyCFunction) modena_model_t_call, METH_KEYWORDS,
866 "Call surrogate model and return outputs" 874 modena_model_t_get_parameters(
modena_model_t *
self,
void *closure)
876 PyObject* pParams = PyList_New(self->parameters_size);
878 for(i = 0; i <
self->parameters_size; i++)
880 PyList_SET_ITEM(pParams, i, PyFloat_FromDouble(self->parameters[i]) );
888 modena_model_t_set_parameters(
modena_model_t *
self, PyObject *value,
void *closure)
895 if(self->parameters_size != PySequence_Size(value))
899 "Wrong number of parameters\n" 915 for(i = 0; i <
self->parameters_size; i++)
917 self->parameters[i] = PyFloat_AsDouble(PyList_GetItem(value, i));
926 static PyGetSetDef modena_model_t_getset[] = {
928 (getter)modena_model_t_get_parameters,
929 (setter)modena_model_t_set_parameters,
937 static int modena_model_t_init
946 PyObject *pParameters=NULL, *
pModel=NULL;
950 static char *kwlist[] = {
"model",
"modelId",
"parameters", NULL};
954 !PyArg_ParseTupleAndKeywords
966 Modena_PyErr_Print();
971 self->pModel = PyObject_CallMethod
973 modena_SurrogateModel,
984 "Surrogate model does not exist" 1001 self->mf = modena_function_new_from_model(
self);
1002 self->function =
self->mf->function;
1004 modena_model_get_minMax(
self);
1006 PyObject *pOutputs = PyObject_GetAttrString(self->pModel,
"outputs");
1007 if(!pOutputs){ Modena_PyErr_Print(); }
1008 self->outputs_size = PyDict_Size(pOutputs);
1009 Py_DECREF(pOutputs);
1011 if(!modena_model_read_substituteModels(
self))
1016 self->argPos_used = malloc(self->inputs_internal_size*
sizeof(
bool));
1018 for(j = 0; j <
self->inputs_internal_size; j++)
1020 self->argPos_used[j] =
false;
1023 for(j = 0; j <
self->substituteModels_size; j++)
1026 for(i = 0; i < sm->map_outputs_size; i++)
1029 self->argPos_used[sm->map_outputs[2*i+1]] =
true;
1035 pParameters = PyObject_GetAttrString(self->pModel,
"parameters");
1036 if(!pParameters){ Modena_PyErr_Print(); }
1040 Py_INCREF(pParameters);
1043 PyObject *pSeq = PySequence_Fast(pParameters,
"expected a sequence");
1047 self->parameters_size == 0
1048 && self->parameters_size != self->mf->parameters_size
1051 PyObject *args = PyTuple_New(2);
1052 PyObject* str = PyString_FromString
1054 "Surrogate model does not have valid parameters" 1056 PyTuple_SET_ITEM(args, 0, str);
1057 PyTuple_SET_ITEM(args, 1, self->pModel);
1061 modena_ParametersNotValid,
1066 Py_DECREF(pParameters);
1070 if(self->parameters_size != PySequence_Size(pParameters))
1074 "Wrong number of parameters %zu %zu\n",
1075 self->parameters_size,
1076 PySequence_Size(pParameters)
1080 PyObject *args = PyTuple_New(2);
1081 PyObject* str = PyString_FromString
1083 "Wrong number of parameters" 1085 PyTuple_SET_ITEM(args, 0, str);
1086 PyTuple_SET_ITEM(args, 1, self->pModel);
1090 modena_ParametersNotValid,
1095 Py_DECREF(pParameters);
1099 self->parameters = malloc(self->parameters_size*
sizeof(
double));
1100 for(i = 0; i <
self->parameters_size; i++)
1102 self->parameters[i] = PyFloat_AsDouble(PyList_GET_ITEM(pSeq, i));
1105 Py_DECREF(pParameters);
1106 if(PyErr_Occurred()){ Modena_PyErr_Print(); }
1113 static PyObject * modena_model_t_new
1127 self->outputs_size = 0;
1128 self->inputs_size = 0;
1129 self->inputs_internal_size = 0;
1130 self->inputs_min = NULL;
1131 self->inputs_max = NULL;
1132 self->argPos_used = NULL;
1133 self->parameters_size = 0;
1134 self->parameters = NULL;
1136 self->function = NULL;
1137 self->substituteModels_size = 0;
1138 self->substituteModels = NULL;
1141 return (PyObject *)
self;
1146 PyTypeObject modena_model_tType = {
1147 PyObject_HEAD_INIT(NULL)
1149 "modena.modena_model_t",
1152 (destructor)modena_model_t_dealloc,
1162 (ternaryfunc)modena_model_t_call,
1167 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1168 "modena_model_t objects",
1175 modena_model_t_methods,
1176 modena_model_t_members,
1177 modena_model_t_getset,
1183 (initproc)modena_model_t_init,
struct modena_model_t modena_model_t
stores a surrogate model
char ** modena_model_parameters_names(const modena_model_t *self)
Function returning the names of the parameters.
char ** modena_model_inputs_names(const modena_model_t *self)
Function returning the names of the inputs.
size_t modena_model_inputs_argPos(const modena_model_t *self, const char *name)
Function determining position of an argument in the input vector.
size_t modena_model_inputs_size(const modena_model_t *self)
Function returning the size of the input vector.
size_t modena_model_outputs_size(const modena_model_t *self)
Function returning the size of the output vector.
modena_model_t * modena_model_new(const char *modelId)
Function fetching a surrogate model from MongoDB.
PyObject_HEAD PyObject * pModel
int modena_model_call(modena_model_t *self, modena_inputs_t *inputs, modena_outputs_t *outputs)
Function calling the surrogate model and checking for errors.
void modena_model_call_no_check(modena_model_t *self, modena_inputs_t *inputs, modena_outputs_t *outputs)
Function calling the surrogate model w/o checking for errors.
void modena_model_destroy(modena_model_t *self)
Function deallocating the memory allocated for the surrogate model.
size_t modena_model_parameters_size(const modena_model_t *self)
Function returning the size of the parameter vector.
size_t modena_model_outputs_argPos(const modena_model_t *self, const char *name)
Function determining position of a result in the output vector.
void modena_model_argPos_check(const modena_model_t *self)
Function checking that the user has queried all input positions.
stores a model and mapping for substitution
char ** modena_model_outputs_names(const modena_model_t *self)
Function returning the names of the outputs.