// assume numFns x numDerivVars x numDerivVars // returns false if conversion failed bool NRELPythonApplicInterface:: python_convert(PyObject *pyma, RealSymMatrixArray &rma) { #ifdef DAKOTA_PYTHON_NUMPY if (userNumpyFlag) { // cannot recurse in this case as we now have a symmetric matrix // (clearer this way anyway) if (!PyArray_Check(pyma) || PyArray_NDIM(pyma) != 3 || PyArray_DIM(pyma,0) != numFns || PyArray_DIM(pyma,1) != numDerivVars || PyArray_DIM(pyma,2) != numDerivVars ) { Cerr << "Python numpy array not 3D of size " << numFns << "x" << numDerivVars << "x" << numDerivVars << "." << std::endl; return(false); } PyArrayObject *pao = (PyArrayObject *) pyma; for (int i=0; i<numFns; ++i) for (int j=0; j<numDerivVars; ++j) for (int k=0; k<=j; ++k) rma[i](j,k) = *(double *)(pao->data + i*(pao->strides[0]) + j*(pao->strides[1]) + k*(pao->strides[2])); } else #endif { PyObject *val; if (!PyList_Check(pyma) || PyList_Size(pyma) != numFns) { Cerr << "Python matrix array must have " << numFns << " rows." << std::endl; return(false); } for (int i=0; i<numFns; ++i) { val = PyList_GetItem(pyma, i); if (PyList_Check(val)) { if (!python_convert(val, rma[i])) return(false); } else { Cerr << "Each row of Python matrix must be a list." << std::endl; Py_DECREF(val); return(false); } } } return(true); }
// assume we're converting numFns x numDerivVars to numDerivVars x // numFns (gradients) returns false if conversion failed bool NRELPythonApplicInterface::python_convert(PyObject *pym, RealMatrix &rm) { #ifdef DAKOTA_PYTHON_NUMPY if (userNumpyFlag) { if (!PyArray_Check(pym) || PyArray_NDIM(pym) != 2 || PyArray_DIM(pym,0) != numFns || PyArray_DIM(pym,1) != numDerivVars) { Cerr << "Python numpy array not 2D of size " << numFns << "x" << numDerivVars << "." << std::endl; return(false); } PyArrayObject *pao = (PyArrayObject *) pym; for (int i=0; i<numFns; ++i) for (int j=0; j<numDerivVars; ++j) rm(j,i) = *(double *)(pao->data + i*(pao->strides[0]) + j*(pao->strides[1])); } else #endif { PyObject *val; if (!PyList_Check(pym) || PyList_Size(pym) != numFns) { Cerr << "Python matrix must have " << numFns << "rows." << std::endl; return(false); } for (int i=0; i<numFns; ++i) { val = PyList_GetItem(pym, i); if (PyList_Check(val)) { // use the helper to convert this column of the gradients if (!python_convert(val, rm[i], numDerivVars)) return(false); } else { Cerr << "Each row of Python matrix must be a list." << std::endl; Py_DECREF(val); return(false); } } } return(true); }
int NRELPythonApplicInterface::derived_map_ac(const Dakota::String& ac_name) { printf ("entered python:derived_map_ac\n"); // probably need to convert all of the following with SWIG or Boost!! // (there is minimal error checking for now) // need to cleanup ref counts on Python objects int fail_code = 0; // probably want to load the modules and functions at construction time, incl. // validation and store the objects for later, but need to resolve use of // analysisDriverIndex // for now we presume a single analysis component containing module:function const std::string& an_comp = analysisComponents[analysisDriverIndex][0]; size_t pos = an_comp.find(":"); std::string module_name = an_comp.substr(0,pos); std::string function_name = an_comp.substr(pos+1); printf ("importing the module %s\n", module_name.c_str()); // import the module and function and test for callable PyObject *pModule = PyImport_Import(PyString_FromString(module_name.c_str())); if (pModule == NULL) { Cerr << "Error (Direct:Python): Failure importing module " << module_name << ".\n Consider setting PYTHONPATH." << std::endl; abort_handler(-1); } printf ("imported the module\n"); // Microsoft compiler chokes on this: // char fn[function_name.size()+1]; char *fn = new char[function_name.size()+1]; strcpy(fn, function_name.c_str()); PyObject *pFunc = PyObject_GetAttrString(pModule, fn); if (!pFunc || !PyCallable_Check(pFunc)) { Cerr << "Error (Direct:Python): Function " << function_name << "not found " << "or not callable" << std::endl; abort_handler(-1); } delete fn; // must use empty tuple here to pass to function taking only kwargs PyObject *pArgs = PyTuple_New(0); PyObject *pDict = PyDict_New(); // convert DAKOTA data types to Python objects (lists and/or numpy arrays) PyObject *cv, *cv_labels, *div, *div_labels, *drv, *drv_labels, *av, *av_labels, *asv, *dvv; python_convert(xC, &cv); python_convert(xCLabels, &cv_labels); python_convert_int(xDI, xDI.length(), &div); python_convert(xDILabels, &div_labels); python_convert(xDR, &drv); python_convert(xDRLabels, &drv_labels); python_convert(xC, xDI, xDR, &av); python_convert(xCLabels, xDILabels, xDRLabels, &av_labels); python_convert_int(directFnASV, directFnASV.size(), &asv); python_convert_int(directFnDVV, directFnASV.size(), &dvv); // TO DO: analysis components // assemble everything into a dictionary to pass to user function // this should eat references to the objects declared above PyDict_SetItem(pDict, PyString_FromString("variables"), PyInt_FromLong((long) numVars)); PyDict_SetItem(pDict, PyString_FromString("functions"), PyInt_FromLong((long) numFns)); PyDict_SetItem(pDict, PyString_FromString("cv"), cv); PyDict_SetItem(pDict, PyString_FromString("cv_labels"), cv_labels); PyDict_SetItem(pDict, PyString_FromString("div"), div); PyDict_SetItem(pDict, PyString_FromString("div_labels"), div_labels); PyDict_SetItem(pDict, PyString_FromString("drv"), drv); PyDict_SetItem(pDict, PyString_FromString("drv_labels"), drv_labels); PyDict_SetItem(pDict, PyString_FromString("av"), av); PyDict_SetItem(pDict, PyString_FromString("av_labels"), av_labels); PyDict_SetItem(pDict, PyString_FromString("asv"), asv); PyDict_SetItem(pDict, PyString_FromString("dvv"), dvv); // Does not appear to exist in Windows version of Dakota, and I don't recall using it: // PyDict_SetItem(pDict, PyString_FromString("fnEvalId"), // PyInt_FromLong((long) fnEvalId)); /////// ///PyDict_SetItem(pDict, PyString_FromString("data"), gData); printf ("I have data at : %lx, NOW WHAT do I do!?\n", pUserData); /////// bp::object * tmp2 = NULL; if (pUserData != NULL) { printf ("Setting raw PyObject in dict\n"); tmp2 = (bp::object*)pUserData; PyDict_SetItem(pDict, PyString_FromString("user_data"), tmp2->ptr()); } else printf("no data\n"); // perform analysis if (outputLevel > NORMAL_OUTPUT) Cout << "Info (Direct:Python): Calling function " << function_name << " in module " << module_name << "." << std::endl; PyObject *retVal = PyObject_Call(pFunc, pArgs, pDict); Py_DECREF(pDict); Py_DECREF(pArgs); Py_DECREF(pFunc); Py_DECREF(pModule); if (!retVal) { // TODO: better error reporting from Python Cerr << "Error (Direct:Python): Unknown error evaluating python " << "function." << std::endl; abort_handler(-1); } bool fn_flag = false; for (int i=0; i<numFns; ++i) if (directFnASV[i] & 1) { fn_flag = true; break; } // process return type as dictionary, else assume list of functions only if (PyDict_Check(retVal)) { // or the user may return a dictionary containing entires fns, fnGrads, // fnHessians, fnLabels, failure (int) // fnGrads, e.g. is a list of lists of doubles // this is where Boost or SWIG could really help // making a lot of assumptions on types being returned PyObject *obj; if (fn_flag) { if ( !(obj = PyDict_GetItemString(retVal, "fns")) ) { Cerr << "Python dictionary must contain list 'fns'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnVals, numFns)) { Py_DECREF(retVal); abort_handler(-1); } } if (gradFlag) { if ( !(obj = PyDict_GetItemString(retVal, "fnGrads")) ) { Cerr << "Python dictionary must contain list 'fnGrads'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnGrads)) { Py_DECREF(retVal); abort_handler(-1); } } if (hessFlag) { if ( !(obj = PyDict_GetItemString(retVal, "fnHessians")) ) { Cerr << "Python dictionary must contain list 'fnHessians'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnHessians)){ Py_DECREF(retVal); abort_handler(-1); } } // optional returns if (obj = PyDict_GetItemString(retVal, "failure")) fail_code = PyInt_AsLong(obj); if (obj = PyDict_GetItemString(retVal, "fnLabels")) { if (!PyList_Check(obj) || PyList_Size(obj) != numFns) { Cerr << "'fnLabels' must be list of length numFns." << std::endl; Py_DECREF(retVal); abort_handler(-1); } for (int i=0; i<numFns; ++i) fnLabels[i] = PyString_AsString(PyList_GetItem(obj, i)); } } else { // asssume list/numpy array containing only functions if (fn_flag) python_convert(retVal, fnVals, numFns); } Py_DECREF(retVal); return(fail_code); }
int PythonInterface::python_run(const String& ac_name) { // probably need to convert all of the following with SWIG or Boost!! // (there is minimal error checking for now) // need to cleanup ref counts on Python objects int fail_code = 0; // probably want to load the modules and functions at construction time, incl. // validation and store the objects for later, but need to resolve use of // analysisDriverIndex // must use empty tuple here to pass to function taking only kwargs PyObject *pArgs = PyTuple_New(0); PyObject *pDict = PyDict_New(); // convert DAKOTA data types to Python objects (lists and/or numpy arrays) PyObject *cv, *cv_labels, *div, *div_labels, *drv, *drv_labels, *av, *av_labels, *asv, *dvv, *an_comps; python_convert(xC, &cv); python_convert_strlist(xCLabels, &cv_labels); python_convert_int(xDI, xDI.length(), &div); python_convert_strlist(xDILabels, &div_labels); python_convert(xDR, &drv); python_convert_strlist(xDRLabels, &drv_labels); python_convert(xC, xDI, xDR, &av); python_convert(xCLabels, xDILabels, xDRLabels, &av_labels); python_convert_int(directFnASV, directFnASV.size(), &asv); python_convert_int(directFnDVV, directFnDVV.size(), &dvv); // send analysis components, or an empty list if (analysisComponents.size() > 0) python_convert_strlist(analysisComponents[analysisDriverIndex], &an_comps); else an_comps = PyList_New(0); // assemble everything into a dictionary to pass to user function // this should eat references to the objects declared above PyDict_SetItem(pDict, PyString_FromString("variables"), PyInt_FromLong((long) numVars)); PyDict_SetItem(pDict, PyString_FromString("functions"), PyInt_FromLong((long) numFns)); PyDict_SetItem(pDict, PyString_FromString("cv"), cv); PyDict_SetItem(pDict, PyString_FromString("cv_labels"), cv_labels); PyDict_SetItem(pDict, PyString_FromString("div"), div); PyDict_SetItem(pDict, PyString_FromString("div_labels"), div_labels); PyDict_SetItem(pDict, PyString_FromString("drv"), drv); PyDict_SetItem(pDict, PyString_FromString("drv_labels"), drv_labels); PyDict_SetItem(pDict, PyString_FromString("av"), av); PyDict_SetItem(pDict, PyString_FromString("av_labels"), av_labels); PyDict_SetItem(pDict, PyString_FromString("asv"), asv); PyDict_SetItem(pDict, PyString_FromString("dvv"), dvv); PyDict_SetItem(pDict, PyString_FromString("analysis_components"), an_comps); PyDict_SetItem(pDict, PyString_FromString("currEvalId"), PyInt_FromLong((long) currEvalId)); // The active analysis_driver is passed in ac_name (in form // module:function); could make module optional. We pass any // analysis components as string arguments to the Python function. size_t pos = ac_name.find(":"); std::string module_name = ac_name.substr(0,pos); std::string function_name = ac_name.substr(pos+1); if (module_name.size() == 0 || function_name.size() == 0) { Cerr << "\nError: invalid Python analysis_driver '" << ac_name << "'\n Should have form 'module:function'." << std::endl; abort_handler(-1); } // import the module and function and test for callable PyObject *pModule = PyImport_Import(PyString_FromString(module_name.c_str())); if (pModule == NULL) { Cerr << "Error (PythonInterface): Failure importing module '" << module_name << "'.\n Consider setting " << "PYTHONPATH." << std::endl; abort_handler(-1); } PyObject *pFunc = PyObject_GetAttrString(pModule, function_name.c_str()); if (!pFunc || !PyCallable_Check(pFunc)) { Cerr << "Error (PythonInterface): Function '" << function_name << "' not found or not callable" << std::endl; abort_handler(-1); } // perform analysis if (outputLevel > NORMAL_OUTPUT) Cout << "Info (PythonInterface): Calling function " << function_name << " in module " << module_name << "." << std::endl; PyObject *retVal = PyObject_Call(pFunc, pArgs, pDict); if (!retVal) { // TODO: better error reporting from Python Cerr << "Error (PythonInterface): Unknown error evaluating python " << "function." << std::endl; abort_handler(-1); } Py_DECREF(pDict); Py_DECREF(pArgs); Py_DECREF(pFunc); Py_DECREF(pModule); // process the return data bool fn_flag = false; for (int i=0; i<numFns; ++i) if (directFnASV[i] & 1) { fn_flag = true; break; } // process return type as dictionary, else assume list of functions only if (PyDict_Check(retVal)) { // or the user may return a dictionary containing entires fns, fnGrads, // fnHessians, fnLabels, failure (int) // fnGrads, e.g. is a list of lists of doubles // this is where Boost or SWIG could really help // making a lot of assumptions on types being returned PyObject *obj; if (fn_flag) { if ( !(obj = PyDict_GetItemString(retVal, "fns")) ) { Cerr << "Python dictionary must contain list 'fns'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnVals, numFns)) { Py_DECREF(retVal); abort_handler(-1); } } if (gradFlag) { if ( !(obj = PyDict_GetItemString(retVal, "fnGrads")) ) { Cerr << "Python dictionary must contain list 'fnGrads'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnGrads)) { Py_DECREF(retVal); abort_handler(-1); } } if (hessFlag) { if ( !(obj = PyDict_GetItemString(retVal, "fnHessians")) ) { Cerr << "Python dictionary must contain list 'fnHessians'" << std::endl; Py_DECREF(retVal); abort_handler(-1); } if (!python_convert(obj, fnHessians)){ Py_DECREF(retVal); abort_handler(-1); } } // optional returns if (obj = PyDict_GetItemString(retVal, "failure")) fail_code = PyInt_AsLong(obj); if (obj = PyDict_GetItemString(retVal, "fnLabels")) { if (!PyList_Check(obj) || PyList_Size(obj) != numFns) { Cerr << "'fnLabels' must be list of length numFns." << std::endl; Py_DECREF(retVal); abort_handler(-1); } for (int i=0; i<numFns; ++i) fnLabels[i] = PyString_AsString(PyList_GetItem(obj, i)); } } else { // asssume list/numpy array containing only functions if (fn_flag) python_convert(retVal, fnVals, numFns); } Py_DECREF(retVal); return(fail_code); }