forked from mom-ocean/MOM6
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python embedding via cpp #5
Open
nikizadehgfdl
wants to merge
4
commits into
homogenizedForcings_Reichl
Choose a base branch
from
python_embedding_via_cpp
base: homogenizedForcings_Reichl
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
46e5797
An effort to embed a Python script in MOM6 via C++
nikizadehgfdl 72b8a0d
An effort to embed a Python script in MOM6 via C++
nikizadehgfdl c7d65e9
Operate with a Python tool on a given MOM6 array
nikizadehgfdl c96a37c
Operate with a Python tool on a given MOM6 array
nikizadehgfdl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
//Inspired from https://github.com/wangsl/python-embedding | ||
//#include "runpyC.h" | ||
#include <stdio.h> | ||
#include <iostream> | ||
#include <cassert> | ||
|
||
#include <Python.h> | ||
#include <numpy/ndarrayobject.h> | ||
|
||
// https://docs.python.org/3/extending/embedding.html | ||
// https://github.com/dusty-nv/jetson-utils/issues/44 | ||
// export PYTHONPATH=.:$PYTHONPATH | ||
|
||
#define FORT(x) x##_ | ||
|
||
static PyObject *py_module = 0; | ||
static PyObject *py_function = 0; | ||
|
||
inline int init_numpy() | ||
{ | ||
if(!PyArray_API) import_array(); | ||
return PyArray_API ? 1 : 0; | ||
} | ||
|
||
static void runpyC_1_1d(const char *py_script_, const char *py_function_, | ||
double *x, const int &n1) | ||
{ | ||
if(!Py_IsInitialized()) Py_Initialize(); | ||
|
||
assert(Py_IsInitialized()); | ||
assert(init_numpy()); | ||
printf("runpyC_1_1d: n1,%d \n", n1); | ||
printf("From runpyC_1_1d: Trying to call %s in %s \n",py_function_,py_script_); | ||
if(!py_module) { | ||
PyObject *py_script = PyUnicode_DecodeFSDefault(py_script_); | ||
assert(py_script); | ||
py_module = PyImport_Import(py_script); | ||
//Interesting: The following assertion fails if | ||
// the py_script has a python bug even outside the function that is called! | ||
// the py_script has import torch | ||
assert(py_module); | ||
Py_DECREF(py_script); | ||
} | ||
if(!py_function) { | ||
assert(py_module); | ||
py_function = PyObject_GetAttrString(py_module, py_function_); | ||
assert(py_function);// This assertation fails if py_function is not found in py_script | ||
assert(PyCallable_Check(py_function)); | ||
} | ||
//Simle tests | ||
//assert(PyObject_CallFunctionObjArgs(py_function, NULL)); //This worked. Printed from the function. | ||
|
||
const npy_intp dim_x [] = { n1 }; | ||
PyObject *x_py = PyArray_SimpleNewFromData(1, dim_x, NPY_DOUBLE, x); | ||
PyObject *pValue; | ||
assert(pValue = PyObject_CallFunctionObjArgs(py_function, x_py, NULL)); | ||
if (pValue != NULL) { | ||
printf("Result of call: %f\n", PyFloat_AsDouble(pValue)); | ||
Py_DECREF(pValue); | ||
} | ||
Py_DECREF(x_py); x_py = 0; | ||
|
||
// PyRun_SimpleString("import sys; sys.stdout.flush()"); | ||
|
||
std::cout.flush(); | ||
} | ||
|
||
static void runpyC_1_3d(const char *py_script_, const char *py_function_, | ||
const char *varname_, | ||
double *x, const int &n1, const int &n2, const int &n3 ) | ||
{ | ||
if(!Py_IsInitialized()) Py_Initialize(); | ||
|
||
assert(Py_IsInitialized()); | ||
assert(init_numpy()); | ||
printf("runpyC_1_3d: varname %s , dims %d,%d,%d \n", varname_, n1,n2,n3); | ||
printf("From runpyC_1_3d: Trying to call %s in %s.py \n",py_function_,py_script_); | ||
if(!py_module) { | ||
PyObject *py_script = PyUnicode_DecodeFSDefault(py_script_); | ||
assert(py_script); | ||
py_module = PyImport_Import(py_script); | ||
//Interesting: The following assertion fails if | ||
// the py_script has a python bug even outside the function that is called! | ||
// the py_script has import torch | ||
assert(py_module && " This assertation fails if the py_script has a python bug.."); | ||
Py_DECREF(py_script); | ||
} | ||
if(!py_function) { | ||
assert(py_module); | ||
py_function = PyObject_GetAttrString(py_module, py_function_); | ||
assert(py_function && " This assertation fails if the function is not found in the script."); //This assertation fails if py_function is not found in py_script | ||
assert(PyCallable_Check(py_function)); | ||
} | ||
//Simle tests | ||
//assert(PyObject_CallFunctionObjArgs(py_function, NULL)); //This worked. Printed from the function. | ||
|
||
const npy_intp dim_x [] = { n1,n2,n3 }; | ||
PyObject *x_py = PyArray_SimpleNewFromData(3, dim_x, NPY_DOUBLE, x); | ||
PyObject *pValue; | ||
assert(pValue = PyObject_CallFunctionObjArgs(py_function, x_py, NULL)); | ||
if (pValue != NULL) { | ||
printf("Result of call: %f\n", PyFloat_AsDouble(pValue)); | ||
Py_DECREF(pValue); | ||
} | ||
Py_DECREF(x_py); x_py = 0; | ||
|
||
// PyRun_SimpleString("import sys; sys.stdout.flush()"); | ||
|
||
std::cout.flush(); | ||
} | ||
|
||
static void py_finalize() | ||
{ | ||
if(py_function) { Py_DECREF(py_function); py_function = 0; } | ||
if(py_module) { Py_DECREF(py_module); py_module = 0; } | ||
if(Py_IsInitialized()) assert(!Py_FinalizeEx()); | ||
std::cout.flush(); | ||
} | ||
|
||
// Fortran interface: NOTE: the name of function should be al lowercase! | ||
extern "C" void FORT(runpyc_1array3d) (const char *py_script, const int &len_py_script, | ||
const char *py_function, const int &len_py_function, | ||
const char *varname, const int &len_varname, | ||
double *x, const int &n1, const int &n2, const int &n3 ) | ||
|
||
{ | ||
char *py_script_ = new char [len_py_script+1]; | ||
assert(py_script); | ||
memcpy(py_script_, py_script, len_py_script*sizeof(char)); | ||
py_script_[len_py_script] = '\0'; | ||
|
||
char *py_function_ = new char [len_py_function+1]; | ||
assert(py_function); | ||
memcpy(py_function_, py_function, len_py_function*sizeof(char)); | ||
py_function_[len_py_function] = '\0'; | ||
|
||
char *varname_ = new char [len_varname+1]; | ||
assert(varname); | ||
memcpy(varname_, varname, len_varname*sizeof(char)); | ||
varname_[len_varname] = '\0'; | ||
|
||
runpyC_1_3d(py_script_, py_function_, varname_, x, n1,n2,n3); | ||
|
||
if(py_script_) { delete [] py_script_; py_script_ = 0; } | ||
if(py_function_) { delete [] py_function_; py_function_ = 0; } | ||
if(varname_) { delete [] varname_; varname_ = 0; } | ||
} | ||
|
||
// Fortran interface: PyFinalize | ||
extern "C" void FORT(pyfinalize)() | ||
{ | ||
py_finalize(); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
!Inspired by https://github.com/wangsl/python-embedding | ||
! | ||
module MOM_python_embedding | ||
implicit none | ||
public runPyF_1_3d | ||
contains | ||
|
||
subroutine runpyF_1_3d(pyScript, pyFunction, varname, x) | ||
character(len=*), intent(in) :: pyScript, pyFunction,varname | ||
real, dimension(:,:,:), intent(inout) :: x | ||
integer :: n1,n2,n3, len_pyScript, len_pyFunction , len_varname | ||
|
||
len_pyScript = Len_Trim(pyScript) | ||
if(pyScript(len_pyScript-2:len_pyScript) .eq. '.py') len_pyScript = len_pyScript-3 | ||
len_pyFunction = Len_Trim(pyFunction) | ||
len_varname = Len_Trim(varname) | ||
|
||
n1 = size(x,1) | ||
n2 = size(x,2) | ||
n3 = size(x,3) | ||
call runpyc_1array3d(pyScript, len_pyScript, pyFunction, len_pyFunction,& | ||
varname, len_varname, x, n1,n2,n3) | ||
|
||
end subroutine runpyF_1_3d | ||
|
||
end module MOM_python_embedding |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#!/bin/env python | ||
#Inspired from https://github.com/wangsl/python-embedding | ||
import sys | ||
import numpy | ||
import matplotlib.pyplot as plt | ||
#A test function with one argument | ||
def py_test1(x) : | ||
print(' **** From py_test1 ****') | ||
print("py_test1: Shape of the input array x : ", x.shape) | ||
print("py_test1: x[4,4,0] x[4,4,-1] : ", x[4,4,0],x[4,4,-1]) | ||
|
||
plt.plot(x[4,4,:]);plt.show(); | ||
|
||
a=numpy.max(x) | ||
print("py_test1: Returning the numpy.max(x): ", a) | ||
|
||
sys.stdout.flush() | ||
return a | ||
|
||
#A test function with two arguments | ||
def py_test2(x,y) : | ||
print(' **** From py_test2 ****',x,y) | ||
sys.stdout.flush() | ||
a=sum(x) | ||
b=sum(y) | ||
return a,b | ||
|
||
#A test function with no arguments | ||
def py_test0(): | ||
print(' **** From py_test0 ****') | ||
sys.stdout.flush() | ||
return | ||
|
||
from math import sin | ||
#import torch | ||
#import numpy #This gives all kinds of library errors at runtime | ||
|
||
def my_test_torch(x, y) : | ||
print(' From Python test: {}'.format(x.size)) | ||
for i in range(x.size) : | ||
x[i] += 1.0 | ||
|
||
a = torch.from_numpy(x) | ||
print(a) | ||
|
||
b = torch.from_numpy(x.astype(numpy.float32)) | ||
print(b) | ||
|
||
if torch.cuda.is_available() : | ||
b_dev = b.cuda() | ||
print(b_dev) | ||
|
||
for i in range(y.size) : | ||
y[i] = 2*numpy.float64(b[i]) + 0.1 | ||
|
||
print(y) | ||
|
||
sys.stdout.flush() | ||
|
||
|
||
if __name__ == '__main__' : | ||
import numpy as np | ||
|
||
x = np.arange(10, dtype=numpy.float64) | ||
print(x) | ||
|
||
y = np.arange(10, dtype=numpy.float64) | ||
print(y) | ||
my_test(x, y) | ||
|
||
print(x) | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could also fail if the python script does not exist or is not found since PYTHONPATH is not set. I had to do this in the workdir setenv PYTHONPATH
pwd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could fail if for any reason the python script could not import a module. I had this assert fail because of "import matplotlib.pyplot as plt" without giving any clue. It was working a few months ago when I tested it. Python script called on its own can import plt, but refuses when called through the exectable. numpy and torch can be imported without a problem.