ASPECT
python_helper.h
Go to the documentation of this file.
1 // ------------------------------------------------------
2 //
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 //
5 // SPDX-FileCopyrightText: Copyright (C) 2025-2026 by the ASPECT authors.
6 //
7 // This file is part of ASPECT.
8 //
9 // Detailed license information governing the source code and
10 // contributions can be found in the folder LICENSES and in
11 // LICENSE and CONTRIBUTING.md at the top level directory.
12 //
13 // ------------------------------------------------------
14 
15 
16 #ifndef _aspect_python_helper_h
17 #define _aspect_python_helper_h
18 
19 #include <aspect/global.h>
21 
22 
23 #ifdef ASPECT_WITH_PYTHON
24 
25 // Python does not like it if this macro is already defined. This happens at
26 // least in some versions of Trilinos and can trigger only with certain unity
27 // build options:
28 #ifdef HAVE_SYS_TIME_H
29 # undef HAVE_SYS_TIME_H
30 #endif
31 #define PY_SSIZE_T_CLEAN
32 #include <Python.h>
33 
34 // Declare that we are compatible with numpy 1.7 API and don't want any
35 // compile warnings for deprecated API calls:
36 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
37 
38 // Define a unique symbol name for the numpy Python API for used when building
39 // the ASPECT executable. This will be used by numpy to declare a static member
40 // variable that will be initialized using the import_array() function (see below).
41 #ifndef PY_ARRAY_UNIQUE_SYMBOL
42 # define PY_ARRAY_UNIQUE_SYMBOL ASPECT_ARRAY_API
43 #endif
44 
45 // NumPY API requires a call to import_array() to be made before usage
46 // but only once per executable. We will define
47 // ASPECT_NUMPY_DEFINE_API in exactly one translation unit per
48 // executable/shared library (in main.cc and any plugin that uses
49 // Python). All other translation units including this header will
50 // therefore define NO_IMPORT_ARRAY that asks numpy to skip defining
51 // import_array().
52 #ifndef ASPECT_NUMPY_DEFINE_API
53 # define NO_IMPORT_ARRAY
54 #endif
55 
56 #include <numpy/arrayobject.h>
57 
58 // Clean up any of the macros defined above. This is important if we
59 // are doing a unity build:
60 #ifdef ASPECT_NUMPY_DEFINE_API
61 # undef ASPECT_NUMPY_DEFINE_API
62 #endif
63 #ifdef NO_IMPORT_ARRAY
64 # undef NO_IMPORT_ARRAY
65 #endif
66 #endif
67 
68 
69 namespace aspect
70 {
71 #ifdef ASPECT_WITH_PYTHON
72  namespace PythonHelper
73  {
82  inline
83  std::unique_ptr<PyObject, void(*)(PyObject *)> vector_to_numpy_object(const std::vector<double> &vec)
84  {
85  const npy_intp size = static_cast<npy_intp>(vec.size());
86 
87  auto deleter = [](PyObject *obj)
88  {
89  Py_DECREF(obj);
90  };
91  if (size == 0)
92  return std::unique_ptr<PyObject, void(*)(PyObject *)>(PyArray_SimpleNew(1, &size, NPY_DOUBLE), deleter);
93  double *data = const_cast<double *>(vec.data());
94  return std::unique_ptr<PyObject, void(*)(PyObject *)>(PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, data), deleter);
95  }
96 
97 
98 
103  inline ::ArrayView<double> numpy_to_array_view(PyObject *obj)
104  {
105  AssertThrow(PyArray_Check(obj), ::ExcMessage("Expected a numpy array"));
106  PyArrayObject *arr = reinterpret_cast<PyArrayObject *>(obj);
107  return ::ArrayView<double>(static_cast<double *>(PyArray_DATA(arr)),
108  static_cast<size_t>(PyArray_SIZE(arr)));
109  }
110 
115  inline
116  PyObject *call_python_function(PyObject *pModule, const char *func_name, PyObject *pArgs = nullptr)
117  {
118  PyObject *pFunc = PyObject_GetAttrString(pModule, func_name);
119  if (!pFunc || !PyCallable_Check(pFunc))
120  AssertThrow(false, ExcMessage(std::string("Failed to load function: ") + func_name));
121 
122  PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
123  Py_DECREF(pFunc);
124 
125  if (pValue == nullptr)
126  {
127  if (PyErr_Occurred())
128  PyErr_Print();
129  AssertThrow(false, ExcMessage(std::string(func_name) + " returned NULL"));
130  }
131  return pValue;
132  }
133  }
134 #endif
135 }
136 
137 
138 #endif
std::vector< index_type > data
#define AssertThrow(cond, exc)
std::size_t size
static ::ExceptionBase & ExcMessage(std::string arg1)