OpenRadioss 2025.1.11
OpenRadioss project
Loading...
Searching...
No Matches
cpp_python_funct.cpp
Go to the documentation of this file.
1//Copyright> OpenRadioss
2//Copyright> Copyright (C) 1986-2025 Altair Engineering Inc.
3//Copyright>
4//Copyright> This program is free software: you can redistribute it and/or modify
5//Copyright> it under the terms of the GNU Affero General Public License as published by
6//Copyright> the Free Software Foundation, either version 3 of the License, or
7//Copyright> (at your option) any later version.
8//Copyright>
9//Copyright> This program is distributed in the hope that it will be useful,
10//Copyright> but WITHOUT ANY WARRANTY; without even the implied warranty of
11//Copyright> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12//Copyright> GNU Affero General Public License for more details.
13//Copyright>
14//Copyright> You should have received a copy of the GNU Affero General Public License
15//Copyright> along with this program. If not, see <https://www.gnu.org/licenses/>.
16//Copyright>
17//Copyright>
18//Copyright> Commercial Alternative: Altair Radioss Software
19//Copyright>
20//Copyright> As an alternative to this open-source version, Altair also offers Altair Radioss
21//Copyright> software under a commercial license. Contact Altair to discuss further if the
22//Copyright> commercial version may interest you: https://www.altair.com/radioss/.
23//
24#include <iostream>
25#include <fstream>
26#include <string>
27#include <sstream>
28#include <cstring>
29#include <vector>
30#include <set>
31#include <map>
32#include <regex>
33#include <iomanip>
34#include <limits>
35#ifndef PYTHON_DISABLED
36#ifdef _WIN32
37/* Windows includes */
38#define NOMINMAX
39#include <windows.h>
40#else
41#include <dlfcn.h>
42#include <dirent.h>
43#endif
44
45#ifdef MYREAL8
46// double precision define my_real as double
47typedef double my_real;
48#else
49typedef float my_real;
50#endif
51
52#include "cpp_python_funct.h"
53#include "cpp_python_sampling.h"
54#include "python_signal.h"
55
56// Note on the python library used:
57//
58//- We check that RAD_PYTHON_PATH is defined and that it points to a valid python library. This variable must contain the full path of the *.[so|dll] file
59// - if the previous check fails, we check that PYTHONHOME is defined and that it points to a valid python library (that contains /lib/libpython*.[so|dll]])
60// - For Linux if the previous check fails, we look for a python library in the default locations (LD_LIBRARY_PATH)
61
62// load a function from a dynamic library
63#ifdef _WIN32
64HMODULE handle = NULL;
65HMODULE python_exec = NULL;
66#else
67void *handle = nullptr;
68#endif
69
70// global variables
71PyObject *pDict = nullptr;
72bool python_initialized = false;
73bool sync_enabled = false; // if true, the python function "sync" will be called at each time step
74// Persistent Python dictionary
75
76// user ids of the nodes that are used in the python functions
77std::set<int> nodes_uid;
78// mapping between user ids and local ids
79std::map<int, int> nodes_uid_to_local_id;
81static PyObject *persistent_dict = nullptr;
82static PyObject *persistent_arg = nullptr;
83
84
85template <std::size_t N>
86std::string element_parenthesis_to_underscore(const std::string &input, const std::array<const char *, N> &keywords)
87{
88 std::string output = input;
89 for (const auto &keyword : keywords)
90 {
91 std::regex pattern(std::string(keyword) + R"(\‍(\s*(\d+)\s*\))");
92 output = std::regex_replace(output, pattern, std::string(keyword) + "_$1");
93 }
94 return output;
95}
96
97std::string node_parenthesis_to_underscore(const std::string &input)
98{
99 std::regex pattern(R"(\b(DX|DY|DZ|AX|AY|AZ|CX|CY|CZ|VX|VY|VZ|ARX|ARY|ARZ|VRX|VRY|VRZ|DRX|DRY|DRZ|MONVOL_VOL|MONVOL_T|MONVOL_A|MONVOL_P)\b\s*\‍(\s*(\d+|ACTIVE_NODE)\s*\))");
100 std::string result = std::regex_replace(input, pattern, "$1_$2");
101 return result;
102}
103
104std::string parenthesis_to_underscore(const std::string &input)
105{
106 std::string result = node_parenthesis_to_underscore(input);
108}
109
110// Function to extract numbers based on the pattern and fill the global set
111void extract_node_uid(const std::string &input)
112{
113 // Coordinates CX_n, CY_n, CZ_n
114 // Displacement DX_n, DY_n, DZ_n
115 // Acceleration AX_n, AY_n, AZ_n
116 // DisplacementR DRX_n, DRY_n, DRZ_n
117 // Velocity VX_n, VY_n , VZ_n
118 // VelocityR VRX_n, VRY_n, VRZ_n
119 // AccelerationR ARX_n, ARY_n, ARZ_n
120 // Regex pattern: non-alphanumeric or start of line, followed by A[XYZ] and underscore and numbers
121 // std::cout<<"input: "<<input<<std::endl;
122 std::regex pattern(R"((?:[^a-zA-Z0-9]|^)[ACDV][R]*[XYZ]_[0-9]+)");
123
124 auto begin = std::sregex_iterator(input.begin(), input.end(), pattern);
125 auto end = std::sregex_iterator();
126
127 for (auto i = begin; i != end; ++i)
128 {
129
130 auto match = *i;
131 std::string match_str = match.str();
132 size_t underscore_pos = match_str.find('_');
133 if (underscore_pos != std::string::npos)
134 {
135 int number = std::stoi(match_str.substr(underscore_pos + 1));
136 nodes_uid.insert(number);
137 }
138 }
139}
140
141// Function to extract unique pairs of <int id, const char * keyword> from the string
142void extract_element_keywords(const std::string &input)
143{
144 for (const auto &keyword : ELEMENT_KEYWORDS)
145 {
146 // std::regex pattern(std::string(keyword) + R"(_(\d+))");
147 std::regex pattern(std::string(R"((?:[^a-zA-Z0-9]|^))") + std::string(keyword) + R"(_(\d+))");
148 auto words_begin = std::sregex_iterator(input.begin(), input.end(), pattern);
149 auto words_end = std::sregex_iterator();
150 for (std::sregex_iterator i = words_begin; i != words_end; ++i)
151 {
152 std::smatch match = *i;
153 int id = std::stoi(match.str(1));
154 element_variables.emplace(id, keyword);
155 // std::cout<<"[PYTHON] keyword found: "<<keyword<<" id: "<<id<<std::endl;
156 }
157 }
158}
159
160// Here is the list of the function that are loaded from the Python library
161// The template is there only to have one version of the code for both Windows and Linux
162template <typename T>
164{
165 python_initialized = true;
166 load_function(h, "Py_Initialize", My_Initialize, python_initialized);
167 load_function(h, "Py_IsInitialized", My_IsInitialized, python_initialized);
168 load_function(h, "Py_Finalize", My_Finalize, python_initialized);
169 load_function(h, "PyDict_GetItemString", MyDict_GetItemString, python_initialized);
170 load_function(h, "PyCallable_Check", MyCallable_Check, python_initialized);
171 load_function(h, "PyTuple_New", MyTuple_New, python_initialized);
172 load_function(h, "PyFloat_FromDouble", MyFloat_FromDouble, python_initialized);
173 load_function(h, "PyObject_CallObject", MyObject_CallObject, python_initialized);
174 load_function(h, "PyImport_AddModule", MyImport_AddModule, python_initialized);
175 load_function(h, "PyModule_GetDict", MyModule_GetDict, python_initialized);
176 load_function(h, "PyRun_SimpleString", MyRun_SimpleString, python_initialized);
177 load_function(h, "PyTuple_SetItem", MyTuple_SetItem, python_initialized);
178 load_function(h, "PyList_SetItem", MyList_SetItem, python_initialized);
181 load_function(h, "PyFloat_AsDouble", MyFloat_AsDouble, python_initialized);
182 load_function(h, "PyDict_SetItemString", MyDict_SetItemString, python_initialized);
183 load_function(h, "PyErr_Fetch", MyErr_Fetch, python_initialized);
184 load_function(h, "PyErr_Display", MyErr_Display, python_initialized);
185 load_function(h, "PyErr_Occurred", MyErr_Occurred, python_initialized);
186 load_function(h, "PyObject_Str", MyObject_Str, python_initialized);
187 load_function(h, "PyUnicode_AsUTF8", MyUnicode_AsUTF8, python_initialized);
190 load_function(h, "PyErr_Clear", MyErr_Clear, python_initialized);
191 load_function(h, "PyLong_FromLong", MyLong_FromLong, python_initialized);
192 load_function(h, "PyLong_FromVoidPtr", MyLong_FromVoidPtr, python_initialized);
193 load_function(h, "PyUnicode_FromString", MyUnicode_FromString, python_initialized);
194 load_function(h, "PyEval_SaveThread", MyEval_SaveThread, python_initialized);
195 load_function(h, "PyEval_RestoreThread", MyEval_RestoreThread, python_initialized);
196 load_function(h, "PyGILState_Ensure", MyGILState_Ensure, python_initialized);
197 load_function(h, "PyGILState_Release", MyGILState_Release, python_initialized);
198}
199
200
201void exit_with_message(const char *message)
202{
203 std::cout << message << std::endl;
204 std::cerr << message << std::endl;
205 My_Finalize();
206 exit(1);
207}
208
209void check_error(int line_number)
210{
211 if (MyErr_Occurred())
212 {
213 //std::cout<<"Error at line: "<<line_number<<std::endl;
214 // Fetch the error
215 PyObject *pType = nullptr, *pValue = nullptr, *pTraceback = nullptr;
216 MyErr_Fetch(&pType, &pValue, &pTraceback);
217 if (pType)
218 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
219 if (pValue)
220 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
221 if (pTraceback)
222 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
223
224 // Print the error
225 //MyErr_Display(pType, pValue, pTraceback);
226 // Decrement reference counts for the error objects
227 My_DecRef(pType);
228 My_DecRef(pValue);
229 My_DecRef(pTraceback);
230 exit_with_message("ERROR: Python function failed");
231 }
232}
233
234void python_signal_handler(int signum) {
235 std::cout << "[PYTHON] Caught signal " << signum << std::endl;
236 std::cerr << "[PYTHON] Caught signal " << signum << std::endl;
237 //How to flush the output buffers before exiting
238 std::cout << std::flush;
239 std::cerr << std::flush;
240 std::cerr.flush();
241 std::cout.flush();
242 //My_Finalize();
243 std::exit(signum);
244}
245
246
247// Call a Python function with a persistent dictionary as its only argument
249{
250 PyObject *pFunc, *pValue;
252 // Retrieve the Python function from the module dictionary
253 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
254 if (MyCallable_Check(pFunc))
255 {
256 // Initialize persistent dictionary on the first call
257 if (!persistent_dict)
258 {
260 if (!persistent_dict)
261 {
262 std::cout << "ERROR: Failed to create persistent dictionary." << std::endl;
263 return nullptr;
264 }
265 // Create a tuple to hold the single dictionary argument
266 persistent_arg = static_cast<PyObject *>(MyTuple_New(1)); // Only 1 argument: the dictionary
267 if (!persistent_arg)
268 {
269 std::cout << "ERROR: Failed to create argument tuple." << std::endl;
270 return nullptr;
271 }
272
273 MyTuple_SetItem(persistent_arg, 0, persistent_dict); // Borrowed reference to persistent_dict Is this the problem????
274 }
275
276 // Set the dictionary in the tuple
277
278 // Call the Python function
279 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, persistent_arg)); // segmentation fault here
280
281 if (pValue != nullptr)
282 {
283 // Function executed successfully
284 // Optionally handle the result (if required)
285 }
286 else
287 {
288 // Handle Python exception
289 std::string func_name_str(func_name);
290 std::cout << "ERROR in Python function " << func_name_str << ": function execution failed" << std::endl;
291 if (MyErr_Occurred())
292 {
293 // Fetch the error details
294 PyObject *pType, *pValue, *pTraceback;
295 MyErr_Fetch(&pType, &pValue, &pTraceback);
296 if (pType)
297 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
298 if (pValue)
299 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
300 if (pTraceback)
301 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
302
303 // Print the error
304 //MyErr_Display(pType, pValue, pTraceback);
305
306 // Decrement reference counts for error objects
307 My_DecRef(pType);
308 My_DecRef(pValue);
309 My_DecRef(pTraceback);
310 exit_with_message("ERROR: Python function failed");
311 }
312 }
314 return pValue;
315 }
316
317 std::cout << "ERROR in Python function: cannot call function: " << func_name << std::endl;
318 return nullptr;
319}
320
321// call a python function with a list of arguments
322PyObject *call_python_function(const char *func_name, double *args, int num_args)
323{
324 check_error(__LINE__);
325 PyObject *pFunc, *pArgs, *pValue;
326 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
327 if (MyCallable_Check(pFunc))
328 {
329 check_error(__LINE__);
330 pArgs = static_cast<PyObject *>(MyTuple_New(num_args));
331 for (size_t i = 0; i < num_args; i++)
332 {
333 MyTuple_SetItem(pArgs, i, static_cast<PyObject *>(MyFloat_FromDouble(args[i])));
334 }
335 check_error(__LINE__);
336 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, pArgs));
337 check_error(__LINE__);
338 My_DecRef(pArgs);
339 if (pValue != nullptr)
340 {
341 // Function executed successfully
342 }
343 else
344 {
345 // convert func_name to a string
346 std::string func_name_str(func_name);
347 std::cout << "ERROR in Python function " << func_name_str << ": function execution failed" << std::endl;
348 if (MyErr_Occurred())
349 {
350 // Fetch the error
351 PyObject *pType = nullptr, *pValue = nullptr, *pTraceback = nullptr;
352 MyErr_Fetch(&pType, &pValue, &pTraceback);
353 if (pType)
354 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
355 if (pValue)
356 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
357 if (pTraceback)
358 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
359
360 // Print the error
361 //MyErr_Display(pType, pValue, pTraceback);
362 // Decrement reference counts for the error objects
363 My_DecRef(pType);
364 My_DecRef(pValue);
365 My_DecRef(pTraceback);
366 exit_with_message("ERROR: Python function failed");
367 }
368 }
369
370 return pValue;
371 }
372 std::cout << "ERROR in Python function: cannot call function: " << func_name << std::endl;
373 return nullptr;
374}
375// call a python function with a list of arguments
376void call_python_function1D_vectors(const char *func_name, std::vector<double> & X, std::vector<double> & Y)
377{
378 PyObject *pFunc, *pArgs, *pValue;
379 const int num_args = X.size();
380 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
381 if (MyCallable_Check(pFunc))
382 {
383 for (size_t i = 0; i < num_args; i++)
384 {
385 pArgs = static_cast<PyObject *>(MyTuple_New(1));
386 MyTuple_SetItem(pArgs, 0, static_cast<PyObject *>(MyFloat_FromDouble(X[i])));
387 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, pArgs));
388 My_DecRef(pArgs);
389
390 if (pValue != nullptr)
391 {
392 // Function executed successfully
393 Y[i]= (MyFloat_AsDouble(pValue));
394 My_DecRef(pValue);
395 }
396 else
397 {
398 MyErr_Clear();
399 Y[i] = static_cast<double>(std::numeric_limits<float>::max());
400 }
401// std::cout<<"X["<<i<<"] = "<<X[i]<<" Y["<<i<<"] = "<<Y[i]<<std::endl;
402 }
403 }
404}
405
406
407void python_execute_code(const std::string &code)
408{
409 MyRun_SimpleString(code.c_str());
410 check_error(__LINE__);
411}
412
413// returns the function name from the function signature, or an empty string if the function name is not found
414std::string extract_function_name(const std::string &signature)
415{
416 if (signature.substr(0, 3) != "def")
417 {
418 std::cout << "ERROR in Python function: signature does not start with 'def'" << std::endl;
419 return "";
420 }
421 std::size_t startPos = signature.find_first_not_of(" ", 3);
422 if (startPos == std::string::npos)
423 {
424 std::cout << "ERROR in Python function: function name not found" << std::endl;
425 return "";
426 }
427 // Find the index of the opening parenthesis
428 std::size_t endPos = signature.find("(", startPos);
429 if (endPos == std::string::npos)
430 {
431 std::cout << "ERROR in Python function: opening parenthesis not found" << std::endl;
432 return "";
433 }
434 // Extract the function name
435 return signature.substr(startPos, endPos - startPos);
436}
437
438// Search for the Python library in the directory specified by the environment variable RAD_PYTHON_PATH
439// If not found, look for PYTHONHOME and search for the library in PYTHONHOME/lib
440#ifdef _WIN32
441// Windows version
443{
444 python_initialized = true;
445
446 // Get the string from the environment variable RAD_PYTHON_PATH
447 char python_path[20000];
448 int path_size = GetEnvironmentVariable("RAD_PYTHON_PATH", python_path, 20000);
449
450 if (path_size == 0)
451 {
452 python_initialized = false;
453 }
454 else
455 {
456 handle = LoadLibrary(python_path);
457 if (!handle)
458 {
459 python_initialized = false;
460 }
461 else
462 {
464 }
465 }
466
468 {
469
470 python_exec = LoadLibrary("python.exe");
471
472 if (python_exec == NULL)
473 {
474 std::cout << "ERROR: No python installation found." << std::endl;
475 std::cout << " Set PATH to Python Installation or set RAD_PYTHON_PATH to the Python library" << std::endl;
476 python_initialized = false;
477 return;
478 }
479
480 char python_filename[2048];
481 DWORD filelen = GetModuleFileName(python_exec, python_filename, 2048);
482 int i = filelen;
483 while (i > 0 && python_filename[i - 1] != '\\')
484 --i;
485 python_filename[i] = '\0';
486
487 strcpy_s(python_path, 20000, python_filename);
488 FreeLibrary(python_exec);
489
490 std::string dir_path = std::string(python_path);
491
492 WIN32_FIND_DATA find_file_data;
493 HANDLE hFind = FindFirstFile((dir_path + "python*.dll").c_str(), &find_file_data);
494
495 if (hFind == INVALID_HANDLE_VALUE)
496 {
497 std::cout << "ERROR: Could not find any python*.dll files in " << dir_path << std::endl;
498 python_initialized = false;
499 return;
500 }
501
502 do
503 {
504 std::string full_dll_path = dir_path + find_file_data.cFileName;
505 handle = LoadLibrary(full_dll_path.c_str());
506
507 if (handle)
508 {
509 python_initialized = true;
510 // std::cout << "Trying python library: " << full_dll_path << std::endl;
513 {
514 // std::cout << "Python library found at " << full_dll_path << std::endl;
515 FindClose(hFind);
517 return;
518 }
519 FreeLibrary(handle);
520 }
521 } while (FindNextFile(hFind, &find_file_data) != 0);
522 FindClose(hFind);
523 }
524 else
525 {
527 }
528}
529
530#else
531
532// Linux only: try to load the python library at the specified path
533bool try_load_library(const std::string &path)
534{
535 bool python_initialized = false;
536 handle = dlopen(path.c_str(), RTLD_LAZY |RTLD_GLOBAL);
537 if (handle)
538 {
539 std::cout << "Trying python library: " << path << std::endl;
542 {
543 std::cout << "INFO: Python library found at " << path << std::endl;
545 if (!My_IsInitialized())
546 {
547 std::cout << "ERROR: My_Initialize failed" << std::endl;
548 python_initialized = false;
549 }
550 }
551 }
552 return python_initialized;
553}
554
556{
557 python_initialized = false;
558 handle = nullptr;
559 // clear the previous errors in dlerror:
560 dlerror();
561 // Get the string from the environment variable RAD_PYTHON_PATH
562 const char *python_path = getenv("RAD_PYTHON_PATH");
563 if (python_path == nullptr)
564 {
565 python_initialized = false;
566 }
567 else
568 {
570 }
571
572 // if RAD_PYTHON_PATH was not found, or if the library was not loaded, try find PYTHONHOME
574 {
575 python_path = getenv("PYTHONHOME");
576 if (python_path)
577 {
578 std::cout << "INFO: searching for python library in PYTHONHOME" << std::endl;
579 std::vector<std::string> possible_dirs = {"/lib64/", "/lib/", "/usr/lib64/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/"};
580 for (const auto &dir : possible_dirs)
581 {
582 std::string dir_path = std::string(python_path) + dir;
583 DIR *d = opendir(dir_path.c_str());
584 if (d)
585 {
586 struct dirent *entry;
587 while ((entry = readdir(d)) != nullptr)
588 {
589 std::string filename(entry->d_name);
590 if (filename.find("libpython") == 0 && filename.find(".so") != std::string::npos)
591 {
592 python_initialized = try_load_library(dir_path + filename);
594 {
595 closedir(d);
596 return;
597 }
598 }
599 }
600 closedir(d);
601 }
602 }
603 }
604 }
605 // if we reach this point, we did not find any python library
606 // we look into some default locations
607 std::cout << " INFO: searching for python library in default locations LD_LIBRARY_PATH" << std::endl;
608 std::vector<std::string> possible_names = {
609 "libpython3.12.so",
610 "libpython3.11.so",
611 "libpython3.10.so",
612 "libpython3.9.so",
613 "libpython3.8.so",
614 "libpython3.7.so",
615 "libpython3.6.so",
616 "libpython3.5.so",
617 "libpython3.4.so",
618 "libpython3.3.so",
619 "libpython3.2.so",
620 "libpython3.1.so",
621 "libpython3.so",
622 "libpython3.0.so",
623 "libpython2.7.so"};
624 for (const auto &name : possible_names)
625 {
626 std::string libname = name;
629 {
630 return;
631 }
632 }
633}
634#endif
635
636
637// C++ functions that can be called from Fortran
638extern "C"
639{
640 void cpp_python_initialize(int *ierror)
641 {
643 { // already initialized
644 return;
645 }
646 // if ierror = 1 on entry, then "-python" is missing from the starter command line, and we will not execute any python code
647 if (*ierror == 1)
648 return;
649 *ierror = 1;
650 // Load Python dynamic library
653 {
654 pDict = MyModule_GetDict(MyImport_AddModule("__main__")); // Get the main module dictionary
655 if (!pDict)
656 {
657 std::cout << "ERROR in Python: fetching main module dictionary" << std::endl;
658 return;
659 }
660 int result = MyRun_SimpleString("import math"); // Import the math module for sin and other functions
661 if (result != 0)
662 {
663 std::cerr << "ERROR: Failed to import math module in Python." << std::endl;
664 // Print Python error traceback
665 if (MyErr_Occurred())
666 {
667 // Fetch the error details
668 PyObject *pType, *pValue, *pTraceback;
669 MyErr_Fetch(&pType, &pValue, &pTraceback);
670 if (pType)
671 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
672 if (pValue)
673 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
674 if (pTraceback)
675 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
676
677 // Print the error
678 //MyErr_Display(pType, pValue, pTraceback);
679
680 // Decrement reference counts for error objects
681 My_DecRef(pType);
682 My_DecRef(pValue);
683 My_DecRef(pTraceback);
684 exit_with_message("ERROR: Python function failed");
685 }
686 }else
687 {
688 *ierror = 0;
689 }
690 check_error(__LINE__);
691 }
692 }
694 {
696 {
697 return;
698 }
699 check_error(__LINE__);
700 const char *code =
701 "if 'initialize_environment' in globals():\n"
702 " initialize_environment()\n";
703 int result = MyRun_SimpleString(code);
704 check_error(__LINE__);
705 }
706
707 void cpp_python_sync(void* pcontext)
708 {
709
710 //std::cout<<"[PYTHON] cpp_python_sync called"<<std::endl;
712 {
713 return;
714 }
715 check_error(__LINE__);
716
717 // cast the context to a double pointer as a PyObject
718 char func_name[100];
719 // func_name = "sync"
720 func_name[0] = 's';
721 func_name[1] = 'y';
722 func_name[2] = 'n';
723 func_name[3] = 'c';
724 func_name[4] = '\0';
725 //std::cout<<"[PYTHON] cpp_python_sync called with function name: "<<func_name<<std::endl;
726
727 PyObject *context = static_cast<PyObject *>(pcontext);
728 PyObject* args = MyTuple_New(1);
729 if(!args)
730 {
731 std::cout << "ERROR: Failed to create Python tuple." << std::endl;
732 }
733 My_IncRef(context);
734 MyTuple_SetItem(args, 0, context); // This steals the reference
735 PyObject *pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
736 if (!pFunc)
737 {
738 std::cout << "ERROR: Python function not found: " << func_name << std::endl;
739 My_DecRef(args);
740 }
741
742 if (!MyCallable_Check(pFunc)) {
743 std::cerr << "[PYTHON] Error: '" << func_name << "' is not callable" << std::endl;
744 My_DecRef(args);
745 }
746
747 PyObject* result = MyObject_CallObject(pFunc, args);
748 if (MyErr_Occurred())
749 {
750 // Fetch the error details
751 PyObject *pType, *pValue, *pTraceback;
752 MyErr_Fetch(&pType, &pValue, &pTraceback);
753 if (pType)
754 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
755 if (pValue)
756 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
757 if (pTraceback)
758 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
759
760 // Decrement reference counts for error objects
761 My_DecRef(pType);
762 My_DecRef(pValue);
763 My_DecRef(pTraceback);
764 exit_with_message("ERROR: Python function failed");
765 }
766
767 My_DecRef(args);
768 check_error(__LINE__);
769
770 }
771
772
774 {
775 My_Finalize();
776 }
777 void cpp_python_execute_code(const char *code)
778 {
779 MyRun_SimpleString(code);
780 check_error(__LINE__);
781
782 }
783
785 {
787 {
788 return;
789 }
790 // initialize TIME and DT to 0
791 check_error(__LINE__);
792
793
794 PyObject *py_TIME = static_cast<PyObject *>(MyFloat_FromDouble(0.0));
795 PyObject *py_DT = static_cast<PyObject *>(MyFloat_FromDouble(0.0));
796 MyDict_SetItemString(pDict, "TIME", py_TIME);
797 MyDict_SetItemString(pDict, "DT", py_DT);
798
799 // loop over the set of nodes
800 for (auto node_uid : nodes_uid)
801 {
802 std::string entity_names[] = {"C", "D", "V", "A", "VR", "AR", "DR"};
803 for (auto name : entity_names)
804 {
805 const double x_values = static_cast<double>(1);
806 const double y_values = static_cast<double>(1);
807 const double z_values = static_cast<double>(1);
808 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
809 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
810 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
811 if (!py_x_values || !py_y_values || !py_z_values)
812 {
813 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
814 return;
815 }
816 std::string x_name = name + "X_" + std::to_string(node_uid);
817 std::string y_name = name + "Y_" + std::to_string(node_uid);
818 std::string z_name = name + "Z_" + std::to_string(node_uid);
819 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
820 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
821 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
822 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
823 // Release the Python objects
824 if (py_x_values != nullptr)
825 My_DecRef(py_x_values);
826 if (py_y_values != nullptr)
827 My_DecRef(py_y_values);
828 if (py_z_values != nullptr)
829 My_DecRef(py_z_values);
830 }
831 }
832 // Initialize all elements keywords to 1
833 for (auto p : element_variables)
834 {
835 double v = static_cast<double>(1);
836 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(v));
837 if (!py_value)
838 {
839 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
840 }
841 // convert p.second (const char *) to std::string
842 std::string keyword(p.second);
843 std::string sname = keyword + "_" + std::to_string(p.first);
844 MyDict_SetItemString(pDict, sname.c_str(), py_value);
845 if (py_value != nullptr)
846 My_DecRef(py_value);
847 }
848 check_error(__LINE__);
849
850 }
851
852 // register a function in the python dictionary
853 void cpp_python_register_function(char *name, char code[], int num_lines)
854 {
855 std::string tmp_string;
856 int current_line = 0;
857 std::stringstream function_code;
858
860 {
861 std::cout << "ERROR: Python not initialized" << std::endl;
862 std::cout << "Make sure that the following python code is safe" << std::endl;
863 std::cout << "and rerun the starter with the -python option." << std::endl;
864 }
865
866 for (int i = 0; current_line < num_lines;)
867 {
868 tmp_string.clear();
869 // Extract characters into the temporary string until a null character is found
870 while (code[i] != '\0')
871 {
872 tmp_string += code[i];
873 i++;
874 }
875 if (current_line == 0)
876 {
877 std::string function_name = extract_function_name(tmp_string);
878 if(function_name == "sync") sync_enabled = true;
879 if (function_name.empty())
880 {
881 std::cout << "ERROR: function name not found in function signature" << std::endl;
882 return;
883 }
884// copy function_name into argument name
885#ifdef _WIN64
886 strcpy_s(name, max_line_length, function_name.c_str());
887#else
888 strcpy(name, function_name.c_str());
889#endif
890 // add the null char at the end of the string
891 name[function_name.size()] = '\0';
892 }
893
894 const std::string s = parenthesis_to_underscore(tmp_string);
896
898 function_code << s << std::endl; // Add the line to the function code
899 i++; // Move past the null character
900 current_line++;
901 }
903 {
904 // initialize the global variables found in the python function
906 python_execute_code(function_code.str());
907 }
908 else
909 {
910 // print the python function to stdout and stderr
911 std::cout << function_code.str() << std::endl;
912 }
913 }
914
915 // works for functions with 2 arguments and 1 return value
916 void cpp_python_call_function(char *name, int num_args, double *args, int num_return, double *return_values)
917 {
919 {
920 return;
921 }
922 //GIL
924 check_error(__LINE__);
925 if (strcmp(name, "initialize_environment") == 0) return;
926 PyObject *result = call_python_function(name, args, num_args);
927 if (result)
928 {
929 return_values[0] = MyFloat_AsDouble(result);
930 My_DecRef(result);
931 } else
932 {
933 exit_with_message("ERROR: Python function failed");
934 }
935 check_error(__LINE__);
936 MyGILState_Release(gstate);
937 }
938
939 void cpp_python_call_function_with_state(char *name, double *return_values)
940 {
942 {
943 return;
944 }
946 check_error(__LINE__);
948 if (result)
949 {
950 *return_values = MyFloat_AsDouble(result);
951 My_DecRef(result);
952 } else {
953 exit_with_message("ERROR: Python function failed");
954 }
955 check_error(__LINE__);
956 MyGILState_Release(gstate);
957 }
958 // this function checks if a function exists in the python dictionary
959 void cpp_python_check_function(char *name, int *error)
960 {
961 PyObject *pFunc;
962 // std::cout << "Checking if function exists: " << name << std::endl;
964 {
965 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, name));
966 if (MyCallable_Check(pFunc))
967 {
968 *error = 0;
969 }
970 else
971 {
972 *error = 1;
973 }
974 }
975 else
976 {
977 *error = 1;
978 }
979
980 // std::cout << "Function exists? " << *error << std::endl;
981 }
982
983 void cpp_python_update_reals(char * basename, int * uid, my_real *reals, int num_reals)
984 {
985 // add BASENAME_$UID = reals[i] to the python dictionary
987 {
988 return;
989 }
990
992 check_error(__LINE__);
993 // Convert C++ doubles to Python objects
994 for (int i = 0; i < num_reals; i++)
995 {
996 double value = static_cast<double>(reals[i]);
997 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(value));
998 if (!py_value)
999 {
1000 std::cerr << "ERROR: Failed to create Python object from C++ double." << std::endl;
1001 return;
1002 }
1003 // Create the key in the format BASENAME_$UID
1004 std::string key = std::string(basename) + "_" + std::to_string(uid[i]);
1005 // Set the item in the Python dictionary
1006 MyDict_SetItemString(pDict, key.c_str(), py_value);
1007 // Release the Python object
1008 My_DecRef(py_value);
1009 }
1010 // Release the Python object
1011 check_error(__LINE__);
1012 MyGILState_Release(gstate);
1013 }
1014
1016 {
1017 if (!python_initialized)
1018 {
1019 // std::cerr << "ERROR: Python is not initialized." << std::endl;
1020 return;
1021 }
1023 check_error(__LINE__);
1024 if (!pDict)
1025 {
1026 std::cerr << "ERROR: Python main module dictionary not initialized." << std::endl;
1027 MyGILState_Release(gstate);
1028 return;
1029 }
1030 // donvert TIME and DT to double precision in TIME2 and DT2
1031 double TIME2 = static_cast<double>(TIME);
1032 double DT2 = static_cast<double>(DT);
1033 // Convert C++ doubles to Python objects
1034 PyObject *py_TIME = static_cast<PyObject *>(MyFloat_FromDouble(TIME2));
1035 PyObject *py_DT = static_cast<PyObject *>(MyFloat_FromDouble(DT2));
1036
1037 if (!py_TIME || !py_DT)
1038 {
1039 std::cerr << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1040 MyGILState_Release(gstate);
1041 return;
1042 }
1043
1044 // Set the Python global variables in the main module's dictionary
1045 MyDict_SetItemString(pDict, "TIME", py_TIME);
1046 MyDict_SetItemString(pDict, "DT", py_DT);
1047
1048 // Release the Python objects
1049 if (py_TIME != nullptr)
1050 My_DecRef(py_TIME);
1051 if (py_DT != nullptr)
1052 My_DecRef(py_DT);
1053 check_error(__LINE__);
1054 MyGILState_Release(gstate);
1055 }
1056 // return the number of nodes that are used in the python functions
1058 {
1059 if (!python_initialized)
1060 {
1061 *num_nodes = 0;
1062 }
1063 else
1064 {
1065 *num_nodes = nodes_uid.size();
1066 }
1067
1068 }
1069
1070 // return the list of nodes (user ids) that are used in the python functions
1071 void cpp_python_get_nodes(int *nodes_uid_array)
1072 {
1074 {
1075 int i = 0;
1076 for (auto node_uid : nodes_uid)
1077 {
1078 // std::cout << "Node uid: " << node_uid << std::endl;
1079 nodes_uid_array[i] = node_uid;
1080 i++;
1081 }
1082 }
1083 }
1084 // itab(i) = uid of node local node i
1085 void cpp_python_create_node_mapping(int *itab, int *num_nodes)
1086 {
1087 // print number of nodes and python_initialized
1088 // std::cout << "Number of nodes: " << *num_nodes << " python_initialized" << python_initialized << std::endl;
1090 {
1091 // loop over the set
1092 for (auto node_uid : nodes_uid)
1093 {
1094 // find i such that itab[i] = node_uid
1095 bool found = false;
1096 for (int i = 0; i < *num_nodes; i++)
1097 {
1098 if (itab[i] == node_uid)
1099 {
1100 nodes_uid_to_local_id[node_uid] = i;
1101 // std::cout << "Node uid: " << node_uid << " local id: " << i << std::endl;
1102 found = true;
1103 break;
1104 }
1105 }
1106 if (!found)
1107 {
1108 std::cout << "Node uid: " << node_uid << " not found in itab" << std::endl;
1109 }
1110 }
1111 check_error(__LINE__);
1112 }
1113 }
1114 // update the global variable sensors from the input arrays
1115 void cpp_python_update_sensors(int *types, int *uids, int *statuses, double *results, int *num_sensors)
1116 {
1117 //std::cout << "[PYTHON] update sensors" << std::endl;
1118 constexpr int sensor_python = 40; // PYTHON
1119 constexpr int sensor_energy = 14; // ENERGY
1120 constexpr int sensor_time = 0; // TIME
1121 constexpr int sensor_accel = 1; // ACCE
1122 constexpr int sensor_dist = 2; // DISP
1123 constexpr int sensor_sens = 3; // SENS
1124 constexpr int sensor_and = 4; // AND
1125 constexpr int sensor_or = 5; // OR
1126 constexpr int sensor_inter = 6; // INTER
1127 constexpr int sensor_rwall = 7; // RWALL
1128 constexpr int sensor_not = 8; // NOT
1129 constexpr int sensor_vel = 9; // VEL
1130 constexpr int sensor_gauge = 10; // GAUGE
1131 constexpr int sensor_rbody = 11; // RBODY
1132 constexpr int sensor_sect = 12; // SECT
1133 constexpr int sensor_work = 13; // WORK
1134 constexpr int sensor_dist_surf = 15; // DIST_SURF
1135 constexpr int sensor_hic = 16; // HIC
1136 constexpr int sensor_temp = 17; // TEMP
1137 // create a python dictionary with associating type to name
1138 const std::map<int, std::string> sensor_type_to_name = {
1139 {sensor_python, "PYTHON"},
1140 {sensor_energy, "ENERGY"},
1141 {sensor_time, "TIME"},
1142 {sensor_accel, "ACCE"},
1143 {sensor_dist, "DIST"},
1144 {sensor_sens, "SENS"},
1145 {sensor_and, "AND"},
1146 {sensor_or, "OR"},
1147 {sensor_inter, "INTER"},
1148 {sensor_rwall, "RWALL"},
1149 {sensor_not, "NOT"},
1150 {sensor_vel, "VEL"},
1151 {sensor_gauge, "GAUGE"},
1152 {sensor_rbody, "RBODY"},
1153 {sensor_sect, "SECT"},
1154 {sensor_work, "WORK"},
1155 {sensor_dist_surf, "DIST_SURF"},
1156 {sensor_hic, "HIC"},
1157 {sensor_temp, "TEMP"}};
1158
1159 if (!python_initialized)
1160 {
1161 return;
1162 }
1163 check_error(__LINE__);
1164 std::ostringstream oss;
1165 oss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::hexfloat;
1166 oss << "sensors = { \n";
1167 for (int i = 0; i < *num_sensors; i++)
1168 {
1169 int type = types[i];
1170 int uid = uids[i];
1171 int status = statuses[i];
1172 oss << " " << uid << " : { 'type' : '" << sensor_type_to_name.at(type) << "', 'status' : " << status;
1173 // depending on the type, the results are different
1174 if (type == sensor_energy)
1175 { // Eint = results[2*(i-1)], Ekin = results[2*(i-1)+1]
1176 oss << ", 'Eint' : float.fromhex('" << results[2 * i] << "'), 'Ekin' : float.fromhex('" << results[2 * i + 1] << "') ";
1177 }
1178 else if (type == sensor_inter || type == sensor_rwall)
1179 { // Force = results[2*(i-1)]
1180 oss << ", 'Force' : float.fromhex('" << results[2 * i] << "') ";
1181 }
1182 else if (type == sensor_dist || type == sensor_dist_surf)
1183 {
1184 oss << ", 'Distance' : float.fromhex('" << results[2 * i] << "') ";
1185 }
1186 else if (type == sensor_gauge)
1187 {
1188 oss << ", 'Pressure' : float.fromhex('" << results[2 * i] << "') ";
1189 }
1190 if (i < *num_sensors - 1)
1191 {
1192 oss << "},\n";
1193 }
1194 else
1195 {
1196 oss << "}\n";
1197 }
1198 }
1199 oss << "\n}";
1200
1201 std::string code = oss.str();
1202 // std::cout<< "Generated code: "<<code<<std::endl;
1203 python_execute_code(code);
1204 // check for errors
1205 check_error(__LINE__);
1206
1207 }
1208
1209 // values is an array of size (3*numnod) containing the values of the nodal entities
1210// call python_update_active_node_values(name_len, temp_name, val)
1211
1212 void cpp_python_update_active_node(int name_len, char *name, double *values)
1213 {
1214 if (!python_initialized)
1215 {
1216 return;
1217 }
1218 check_error(__LINE__);
1219 double x_values, y_values, z_values;
1220 // loop over the map nodes_uid_to_local_id
1221 {
1222 x_values = static_cast<double>(values[0]);
1223 y_values = static_cast<double>(values[1]);
1224 z_values = static_cast<double>(values[2]);
1225 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
1226 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
1227 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
1228 if (!py_x_values || !py_y_values || !py_z_values)
1229 {
1230 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1231 return;
1232 }
1233 // Set the Python global variables in the main module's dictionary
1234 std::string x_name = std::string(name) + "X_ACTIVE_NODE";
1235 std::string y_name = std::string(name) + "Y_ACTIVE_NODE";
1236 std::string z_name = std::string(name) + "Z_ACTIVE_NODE";
1237 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
1238 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
1239 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
1240 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
1241 // Release the Python objects
1242 if (py_x_values != nullptr)
1243 My_DecRef(py_x_values);
1244 if (py_y_values != nullptr)
1245 My_DecRef(py_y_values);
1246 if (py_z_values != nullptr)
1247 My_DecRef(py_z_values);
1248 check_error(__LINE__);
1249
1250 }
1251 }
1253 { // set ACTIVE_NODE as id, and ACTIVE_NODE_UID as uid
1254 if (!python_initialized)
1255 {
1256 return;
1257 }
1258 check_error(__LINE__);
1259 // Set the Python global variables in the main module's dictionary
1260 std::string id_name = "ACTIVE_NODE";
1261 std::string uid_name = "ACTIVE_NODE_UID";
1262 MyDict_SetItemString(pDict, id_name.c_str(), static_cast<PyObject *>(MyLong_FromLong(static_cast<long>(id))));
1263 MyDict_SetItemString(pDict, uid_name.c_str(), static_cast<PyObject *>(MyLong_FromLong(static_cast<long>(uid))));
1264 check_error(__LINE__);
1265
1266 }
1267
1268
1269 // values is an array of size (3*numnod) containing the values of the nodal entities
1270 void cpp_python_update_nodal_entity(int numnod, int name_len, char *name, my_real *values)
1271 {
1272 if (!python_initialized)
1273 {
1274 return;
1275 }
1276
1277 check_error(__LINE__);
1278 double x_values, y_values, z_values;
1279 // loop over the map nodes_uid_to_local_id
1280 for (auto it = nodes_uid_to_local_id.begin(); it != nodes_uid_to_local_id.end(); ++it)
1281 {
1282 int node_uid = it->first;
1283 int local_id = it->second;
1284 if(local_id > numnod-1)
1285 {
1286 std::cout << "ERROR: local_id " << local_id << " is greater than numnod " << numnod << std::endl;
1287 return;
1288 }
1289 x_values = static_cast<double>(values[3 * local_id]);
1290 y_values = static_cast<double>(values[3 * local_id + 1]);
1291 z_values = static_cast<double>(values[3 * local_id + 2]);
1292 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
1293 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
1294 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
1295 if (!py_x_values || !py_y_values || !py_z_values)
1296 {
1297 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1298 return;
1299 }
1300 // Set the Python global variables in the main module's dictionary
1301 std::string x_name = std::string(name) + "X_" + std::to_string(node_uid);
1302 std::string y_name = std::string(name) + "Y_" + std::to_string(node_uid);
1303 std::string z_name = std::string(name) + "Z_" + std::to_string(node_uid);
1304 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
1305 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
1306 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
1307 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
1308 // Release the Python objects
1309 if (py_x_values != nullptr)
1310 My_DecRef(py_x_values);
1311 if (py_y_values != nullptr)
1312 My_DecRef(py_y_values);
1313 if (py_z_values != nullptr)
1314 My_DecRef(py_z_values);
1315
1316 check_error(__LINE__);
1317 }
1318 }
1319
1320 // update values for elemental entities found in the Python function
1321 void cpp_python_update_elemental_entity(char *name, double value, int uid)
1322 {
1323 double v = static_cast<double>(value);
1324 check_error(__LINE__);
1325 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(v));
1326 if (!py_value)
1327 {
1328 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1329 }
1330 std::string sname = std::string(name) + "_" + std::to_string(uid);
1331 // std::cout<<"[PYTHON] update elemental entity: "<<sname<<" value: "<<v<<std::endl;
1332 MyDict_SetItemString(pDict, sname.c_str(), py_value);
1333 if (py_value != nullptr)
1334 My_DecRef(py_value);
1335 check_error(__LINE__);
1336 }
1337
1338 // return the size of the KeywordPairs element_variables
1340 {
1341 *nb = element_variables.size();
1342 }
1343
1344 void cpp_python_get_elemental_entity(int nb, char *name, int *uid)
1345 {
1346 size_t n = static_cast<size_t>(nb - 1);
1348 for (int i = 0; i < max_variable_length; i++)
1349 {
1350 name[i] = '\0';
1351 }
1352 // copy user id
1353 *uid = p.first;
1354 // copy variable name
1355#ifdef _WIN64
1356 strcpy_s(name, max_variable_length, p.second);
1357#else
1358 strcpy(name, p.second);
1359#endif
1360 }
1361
1362 void cpp_python_sample_function(char *name, double *x, double *y, int n)
1363 {
1364 //write the name
1365 constexpr size_t N = 10000; // Number of points
1366 double x_max = 1e+6;
1367 std::vector<double> Xtmp = initial_sampling(x_max,N);
1368 std::vector<double> X(2*N, 0.0);
1369 double scale = x_max / N;
1370
1371 // X = -Xtmp(N) .. -Xtmp(1) Xtmp(1) .. Xtmp(N)
1372 for (size_t i = 0; i < N; i++)
1373 {
1374 X[i] = -scale * Xtmp[N - i - 1];
1375 }
1376 for (size_t i = 0; i < N; i++)
1377 {
1378 X[i + N] = scale * Xtmp[i];
1379 }
1380 // I would like to symmetrically sample the function around 0, so I will sample the function at -X and X
1381 //Y of size N, filled with 0
1382 std::vector<double> Y(X.size(), 0.0);
1383 // evaluate the function at all X values using cpp_
1385 //Sample the function to get n points:
1386 std::vector<double> new_x = select_points(X,Y,size_t(n));
1387 std::vector<double> new_y(n, 0.0);
1388 call_python_function1D_vectors(name, new_x, new_y);
1389 //sizes:
1390 // copy the values to the output arrays
1391 for (int i = 0; i < n; i++)
1392 {
1393 x[i] = static_cast<my_real>(new_x[i]);
1394 y[i] = static_cast<my_real>(new_y[i]);
1395 }
1396 }
1397
1398
1399//
1400// subroutine python_add_ints_to_dict(context, name, len_name, values, nvalues) &
1401// bind(c, name="cpp_python_add_ints_to_dict")
1402// use iso_c_binding
1403// type(c_ptr), value, intent(in) :: context
1404// integer(kind=c_int), value, intent(in) :: nvalues
1405// character(kind=c_char), dimension(len_name), intent(in) :: name
1406// integer(kind=c_int), dimension(nvalues), intent(in) :: values
1407// end subroutine python_add_ints_to_dict
1408 //subroutine python_add_doubles_to_dict(context, name, len_name, values, nvalues) &
1409void cpp_python_add_ints_to_dict(void* context_ptr, const char* name, int len_name, int* values, int nvalues)
1410{ // expose the array without copying
1411 if (!python_initialized)
1412 {
1413 return;
1414 }
1415 check_error(__LINE__);
1416 PyObject * context = static_cast<PyObject*>(context_ptr);
1417 char ptr_key[100],size_key[100],type_key[100];
1418 snprintf(ptr_key, sizeof(ptr_key), "%s_ptr", name);
1419 snprintf(size_key, sizeof(size_key), "%s_size", name);
1420 snprintf(type_key, sizeof(type_key), "%s_type", name);
1421 PyObject* ptr_value = MyLong_FromVoidPtr(values);
1422 PyObject* size_value = MyLong_FromLong(static_cast<long>(nvalues));
1423 PyObject* type_value = MyUnicode_FromString("int");
1424
1425 // set the values in the context dictionary
1426 MyDict_SetItemString(context, ptr_key, ptr_value);
1427 MyDict_SetItemString(context, size_key, size_value);
1428 MyDict_SetItemString(context, type_key, type_value);
1429
1430 // release the references
1431 My_DecRef(ptr_value);
1432 My_DecRef(size_value);
1433 My_DecRef(type_value);
1434 check_error(__LINE__);
1435
1436}
1437
1438void cpp_python_add_doubles_to_dict(void* context_ptr, const char* name, int len_name, double* values, int nvalues)
1439{ // expose the array without copying
1440 if (!python_initialized)
1441 {
1442 return;
1443 }
1444 check_error(__LINE__);
1445 PyObject * context = static_cast<PyObject*>(context_ptr);
1446 char ptr_key[100],size_key[100],type_key[100];
1447 snprintf(ptr_key, sizeof(ptr_key), "%s_ptr", name);
1448 snprintf(size_key, sizeof(size_key), "%s_size", name);
1449 snprintf(type_key, sizeof(type_key), "%s_type", name);
1450 PyObject* ptr_value = MyLong_FromVoidPtr(values);
1451 PyObject* size_value = MyLong_FromLong(static_cast<long>(nvalues));
1452 PyObject* type_value = MyUnicode_FromString("double");
1453 // set the values in the context dictionary
1454 MyDict_SetItemString(context, ptr_key, ptr_value);
1455 MyDict_SetItemString(context, size_key, size_value);
1456 MyDict_SetItemString(context, type_key, type_value);
1457 // release the references
1458 My_DecRef(ptr_value);
1459 My_DecRef(size_value);
1460 My_DecRef(type_value);
1461 check_error(__LINE__);
1462}
1463 // set the values in the context dictionary
1464
1465
1467 check_error(__LINE__);
1468 PyObject* context = MyDict_New();
1469 if (!context) {
1470 return NULL;
1471 }
1472 return context;
1473 check_error(__LINE__);
1474}
1475
1476void cpp_python_free_context(void* context) {
1477 if (context) {
1478 My_DecRef(static_cast<PyObject*>(context));
1479 }
1480}
1484
1486 MyEval_RestoreThread(saved_state);
1487}
1488} // extern "C"
1489
1490#else
1491// dummy functions
1492extern "C"
1493{
1494 void cpp_python_initialize(int *ok)
1495 {
1496 // ok = 0; if not ok
1497 *ok = 0;
1498 // std::cout << "ERROR: python not enabled" << std::endl;
1499 }
1500 void cpp_python_finalize()
1501 {
1502 // std::cout << "ERROR: python not enabled" << std::endl;
1503 }
1504 void cpp_python_execute_code(const char *code)
1505 {
1506 // std::cout << "ERROR: python not enabled" << std::endl;
1507 }
1508 void cpp_python_register_function(char *name, char code[500][1000], int num_lines)
1509 {
1510 // std::cout << "ERROR: python not enabled" << std::endl;
1511 }
1512 void cpp_python_call_function(char *name, int num_args, double *args, int num_return, double *return_values)
1513 {
1514 std::cout << "ERROR: python not enabled" << std::endl;
1515 }
1516 void cpp_python_sample_function(char *name, double*x, double*y, int n)
1517 {
1518 std::cout << "ERROR: python not enabled" << std::endl;
1519 }
1521 {
1522 std::cout << "ERROR: python not enabled" << std::endl;
1523 }
1524 void cpp_python_check_function(char *name, int *error)
1525 {
1526 // std::cout << "ERROR: python not enabled" << std::endl;
1527 }
1528 void cpp_python_update_time(double TIME, double DT) {}
1529 void cpp_python_get_number_of_nodes(int *num_nodes) {}
1530 // return the list of nodes (user ids) that are used in the python functions
1531 void cpp_python_get_nodes(int *nodes_uid_array) {}
1532 void cpp_python_create_node_mapping(int *itab, int *num_nodes) {}
1533 void cpp_python_update_nodal_entity(int numnod, int name_len, char *name, my_real *values) {}
1534 void cpp_python_update_elemental_entity(char *name, my_real value, int uid) {}
1536 void cpp_python_get_elemental_entity(int nb, char *name, int *uid) {}
1538 void cpp_python_update_sensors(int types, int *uids, int *statuses, double *results, int *num_sensors){}
1539 void* py_begin_allow_threads() {return nullptr;}
1540 void py_end_allow_threads(void* saved_state) {}
1541
1542}
1543
1544#endif
std::string element_parenthesis_to_underscore(const std::string &input, const std::array< const char *, N > &keywords)
void cpp_python_update_sensors(int *types, int *uids, int *statuses, double *results, int *num_sensors)
void python_signal_handler(int signum)
std::string parenthesis_to_underscore(const std::string &input)
void py_end_allow_threads(PyThreadState *saved_state)
void exit_with_message(const char *message)
void cpp_python_update_time(my_real TIME, my_real DT)
void * cpp_python_create_context()
void cpp_python_create_node_mapping(int *itab, int *num_nodes)
void check_error(int line_number)
void python_load_library()
void cpp_python_finalize()
std::map< int, int > nodes_uid_to_local_id
KeywordPairs element_variables
void cpp_python_get_nodes(int *nodes_uid_array)
bool try_load_library(const std::string &path)
PyObject * pDict
void cpp_python_update_nodal_entity(int numnod, int name_len, char *name, my_real *values)
void cpp_python_sample_function(char *name, double *x, double *y, int n)
void cpp_python_register_function(char *name, char code[], int num_lines)
void cpp_python_update_reals(char *basename, int *uid, my_real *reals, int num_reals)
void cpp_python_check_function(char *name, int *error)
void cpp_python_call_function(char *name, int num_args, double *args, int num_return, double *return_values)
void cpp_python_add_ints_to_dict(void *context_ptr, const char *name, int len_name, int *values, int nvalues)
void cpp_python_update_active_node(int name_len, char *name, double *values)
void * handle
void cpp_python_initialize_global_variables()
void cpp_python_add_doubles_to_dict(void *context_ptr, const char *name, int len_name, double *values, int nvalues)
bool python_initialized
void cpp_python_load_environment()
void cpp_python_update_active_node_ids(int id, int uid)
void extract_element_keywords(const std::string &input)
PyObject * call_python_function(const char *func_name, double *args, int num_args)
PyThreadState * py_begin_allow_threads()
void cpp_python_get_number_of_nodes(int *num_nodes)
void cpp_python_initialize(int *ierror)
static PyObject * persistent_arg
std::string node_parenthesis_to_underscore(const std::string &input)
void load_functions(T h, bool &python_initialized)
void python_execute_code(const std::string &code)
void cpp_python_call_function_with_state(char *name, double *return_values)
void cpp_python_get_number_elemental_entities(int *nb)
void cpp_python_update_elemental_entity(char *name, double value, int uid)
void cpp_python_execute_code(const char *code)
void cpp_python_free_context(void *context)
void call_python_function1D_vectors(const char *func_name, std::vector< double > &X, std::vector< double > &Y)
PyObject * call_python_function_with_state(const char *func_name)
void cpp_python_sync(void *pcontext)
static PyObject * persistent_dict
std::string extract_function_name(const std::string &signature)
bool sync_enabled
void cpp_python_get_elemental_entity(int nb, char *name, int *uid)
void extract_node_uid(const std::string &input)
std::set< int > nodes_uid
T_PyEval_RestoreThread MyEval_RestoreThread
T_PyModule_GetDict MyModule_GetDict
T_PyList_New MyList_New
T_PyGILState_Release MyGILState_Release
T_PyErr_Display MyErr_Display
T_Py_DecRef My_DecRef
int PyGILState_STATE
T_PyTuple_SetItem MyTuple_SetItem
T_PyCallable_Check MyCallable_Check
T_PyLong_FromLong MyLong_FromLong
T_PyDict_New MyDict_New
void * PyObject
T_PyLong_FromVoidPtr MyLong_FromVoidPtr
constexpr std::array< const char *, 89 > ELEMENT_KEYWORDS
T_PyUnicode_FromString MyUnicode_FromString
T_PyUnicode_AsUTF8 MyUnicode_AsUTF8
T_PyDict_GetItemString MyDict_GetItemString
KeywordPair get_keyword_pair(const KeywordPairs &keywordPairs, size_t n)
#define max_variable_length
T_PyErr_Clear MyErr_Clear
std::pair< int, const char * > KeywordPair
T_PyGILState_Ensure MyGILState_Ensure
T_PyErr_Occurred MyErr_Occurred
T_Py_IsInitialized My_IsInitialized
T_Py_Initialize My_Initialize
struct _ts PyThreadState
#define max_line_length
T_PyErr_Fetch MyErr_Fetch
T_Py_Finalize My_Finalize
T_Py_IncRef My_IncRef
T_PyFloat_AsDouble MyFloat_AsDouble
T_PyImport_AddModule MyImport_AddModule
std::set< std::pair< int, const char * >, ComparePairs > KeywordPairs
void load_function(void *h, const std::string &func_name, T &func_ptr, bool &python_initialized)
T_PyDict_SetItemString MyDict_SetItemString
T_PyTuple_New MyTuple_New
T_PyRun_SimpleString MyRun_SimpleString
T_PyList_SetItem MyList_SetItem
T_PyObject_CallObject MyObject_CallObject
T_PyObject_Str MyObject_Str
T_PyFloat_FromDouble MyFloat_FromDouble
T_PyEval_SaveThread MyEval_SaveThread
std::vector< double > initial_sampling(double x_max, size_t n)
std::vector< double > select_points(const std::vector< double > &x, const std::vector< double > &F_values, size_t n_points)
#define my_real
Definition cppsort.cpp:32
end[inform, rinform, sol, inst, schur, redrhs, pivnul_list, sym_perm, uns_perm, icntl, cntl, colsca_out, rowsca_out, keep_out, dkeep_out]
Definition dmumps.m:40
#define N
void activate_signal_handling(SignalHandler handler, int signal=SIGINT)
void restore_default_signal_handling(int signal=SIGINT)
n
subroutine sensor_and(nsensor, sensor_tab, sens)
Definition sensor_and.F:31
subroutine sensor_dist(sensor, x, xsens)
Definition sensor_dist.F:32
subroutine sensor_dist_surf(sensor, x, igrsurf)
subroutine sensor_energy(sensor, isens, subset, partsav2, nsensor, sensor_struct)
subroutine sensor_gauge(sensor, gauge)
subroutine sensor_hic(sensor, accn, accel)
Definition sensor_hic.F:33
subroutine sensor_not(nsensor, sensor_tab, sens)
Definition sensor_not.F:31
subroutine sensor_or(nsensor, sensor_tab, sens)
Definition sensor_or.F:31
subroutine sensor_rbody(sensor, dimfb, stabs, tabs, fbsav6)
subroutine sensor_rwall(sensor, nprw, dimfb, stabs, tabs, fbsav6)
subroutine sensor_sens(nsensor, sensor_tab, sens)
Definition sensor_sens.F:31
subroutine sensor_temp(sensor, isens, igrnod)
Definition sensor_temp.F:32
subroutine sensor_time(sensor, time, timestep)
Definition sensor_time.F:33
subroutine sensor_vel(sensor, v)
Definition sensor_vel.F:34
subroutine sensor_work(sensor, x, xsens, dimfb, stabs, tabs, fbsav6)
Definition sensor_work.F:33