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}
195
196
197void exit_with_message(const char *message)
198{
199 std::cout << message << std::endl;
200 std::cerr << message << std::endl;
201 My_Finalize();
202 exit(1);
203}
204
205void check_error(int line_number)
206{
207 if (MyErr_Occurred())
208 {
209 //std::cout<<"Error at line: "<<line_number<<std::endl;
210 // Fetch the error
211 PyObject *pType = nullptr, *pValue = nullptr, *pTraceback = nullptr;
212 MyErr_Fetch(&pType, &pValue, &pTraceback);
213 if (pType)
214 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
215 if (pValue)
216 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
217 if (pTraceback)
218 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
219
220 // Print the error
221 //MyErr_Display(pType, pValue, pTraceback);
222 // Decrement reference counts for the error objects
223 My_DecRef(pType);
224 My_DecRef(pValue);
225 My_DecRef(pTraceback);
226 exit_with_message("ERROR: Python function failed");
227 }
228}
229
230void python_signal_handler(int signum) {
231 std::cout << "[PYTHON] Caught signal " << signum << std::endl;
232 std::cerr << "[PYTHON] Caught signal " << signum << std::endl;
233 //How to flush the output buffers before exiting
234 std::cout << std::flush;
235 std::cerr << std::flush;
236 std::cerr.flush();
237 std::cout.flush();
238 //My_Finalize();
239 std::exit(signum);
240}
241
242
243// Call a Python function with a persistent dictionary as its only argument
245{
246 PyObject *pFunc, *pValue;
248 // Retrieve the Python function from the module dictionary
249 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
250 if (MyCallable_Check(pFunc))
251 {
252 // Initialize persistent dictionary on the first call
253 if (!persistent_dict)
254 {
256 if (!persistent_dict)
257 {
258 std::cout << "ERROR: Failed to create persistent dictionary." << std::endl;
259 return nullptr;
260 }
261 // Create a tuple to hold the single dictionary argument
262 persistent_arg = static_cast<PyObject *>(MyTuple_New(1)); // Only 1 argument: the dictionary
263 if (!persistent_arg)
264 {
265 std::cout << "ERROR: Failed to create argument tuple." << std::endl;
266 return nullptr;
267 }
268
269 MyTuple_SetItem(persistent_arg, 0, persistent_dict); // Borrowed reference to persistent_dict Is this the problem????
270 }
271
272 // Set the dictionary in the tuple
273
274 // Call the Python function
275 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, persistent_arg)); // segmentation fault here
276
277 if (pValue != nullptr)
278 {
279 // Function executed successfully
280 // Optionally handle the result (if required)
281 }
282 else
283 {
284 // Handle Python exception
285 std::string func_name_str(func_name);
286 std::cout << "ERROR in Python function " << func_name_str << ": function execution failed" << std::endl;
287 if (MyErr_Occurred())
288 {
289 // Fetch the error details
290 PyObject *pType, *pValue, *pTraceback;
291 MyErr_Fetch(&pType, &pValue, &pTraceback);
292 if (pType)
293 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
294 if (pValue)
295 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
296 if (pTraceback)
297 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
298
299 // Print the error
300 //MyErr_Display(pType, pValue, pTraceback);
301
302 // Decrement reference counts for error objects
303 My_DecRef(pType);
304 My_DecRef(pValue);
305 My_DecRef(pTraceback);
306 exit_with_message("ERROR: Python function failed");
307 }
308 }
310 return pValue;
311 }
312
313 std::cout << "ERROR in Python function: cannot call function: " << func_name << std::endl;
314 return nullptr;
315}
316
317// call a python function with a list of arguments
318PyObject *call_python_function(const char *func_name, double *args, int num_args)
319{
320 check_error(__LINE__);
321 PyObject *pFunc, *pArgs, *pValue;
322 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
323 if (MyCallable_Check(pFunc))
324 {
325 check_error(__LINE__);
326 pArgs = static_cast<PyObject *>(MyTuple_New(num_args));
327 for (size_t i = 0; i < num_args; i++)
328 {
329 MyTuple_SetItem(pArgs, i, static_cast<PyObject *>(MyFloat_FromDouble(args[i])));
330 }
331 check_error(__LINE__);
332 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, pArgs));
333 check_error(__LINE__);
334 My_DecRef(pArgs);
335 if (pValue != nullptr)
336 {
337 // Function executed successfully
338 }
339 else
340 {
341 // convert func_name to a string
342 std::string func_name_str(func_name);
343 std::cout << "ERROR in Python function " << func_name_str << ": function execution failed" << std::endl;
344 if (MyErr_Occurred())
345 {
346 // Fetch the error
347 PyObject *pType = nullptr, *pValue = nullptr, *pTraceback = nullptr;
348 MyErr_Fetch(&pType, &pValue, &pTraceback);
349 if (pType)
350 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
351 if (pValue)
352 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
353 if (pTraceback)
354 std::cout<<"[PYTHON]"<< MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
355
356 // Print the error
357 //MyErr_Display(pType, pValue, pTraceback);
358 // Decrement reference counts for the error objects
359 My_DecRef(pType);
360 My_DecRef(pValue);
361 My_DecRef(pTraceback);
362 exit_with_message("ERROR: Python function failed");
363 }
364 }
365
366 return pValue;
367 }
368 std::cout << "ERROR in Python function: cannot call function: " << func_name << std::endl;
369 return nullptr;
370}
371// call a python function with a list of arguments
372void call_python_function1D_vectors(const char *func_name, std::vector<double> & X, std::vector<double> & Y)
373{
374 PyObject *pFunc, *pArgs, *pValue;
375 const int num_args = X.size();
376 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
377 if (MyCallable_Check(pFunc))
378 {
379 for (size_t i = 0; i < num_args; i++)
380 {
381 pArgs = static_cast<PyObject *>(MyTuple_New(1));
382 MyTuple_SetItem(pArgs, 0, static_cast<PyObject *>(MyFloat_FromDouble(X[i])));
383 pValue = static_cast<PyObject *>(MyObject_CallObject(pFunc, pArgs));
384 My_DecRef(pArgs);
385
386 if (pValue != nullptr)
387 {
388 // Function executed successfully
389 Y[i]= (MyFloat_AsDouble(pValue));
390 My_DecRef(pValue);
391 }
392 else
393 {
394 MyErr_Clear();
395 Y[i] = static_cast<double>(std::numeric_limits<float>::max());
396 }
397// std::cout<<"X["<<i<<"] = "<<X[i]<<" Y["<<i<<"] = "<<Y[i]<<std::endl;
398 }
399 }
400}
401
402
403void python_execute_code(const std::string &code)
404{
405 MyRun_SimpleString(code.c_str());
406 check_error(__LINE__);
407}
408
409// returns the function name from the function signature, or an empty string if the function name is not found
410std::string extract_function_name(const std::string &signature)
411{
412 if (signature.substr(0, 3) != "def")
413 {
414 std::cout << "ERROR in Python function: signature does not start with 'def'" << std::endl;
415 return "";
416 }
417 std::size_t startPos = signature.find_first_not_of(" ", 3);
418 if (startPos == std::string::npos)
419 {
420 std::cout << "ERROR in Python function: function name not found" << std::endl;
421 return "";
422 }
423 // Find the index of the opening parenthesis
424 std::size_t endPos = signature.find("(", startPos);
425 if (endPos == std::string::npos)
426 {
427 std::cout << "ERROR in Python function: opening parenthesis not found" << std::endl;
428 return "";
429 }
430 // Extract the function name
431 return signature.substr(startPos, endPos - startPos);
432}
433
434// Search for the Python library in the directory specified by the environment variable RAD_PYTHON_PATH
435// If not found, look for PYTHONHOME and search for the library in PYTHONHOME/lib
436#ifdef _WIN32
437// Windows version
439{
440 python_initialized = true;
441
442 // Get the string from the environment variable RAD_PYTHON_PATH
443 char python_path[20000];
444 int path_size = GetEnvironmentVariable("RAD_PYTHON_PATH", python_path, 20000);
445
446 if (path_size == 0)
447 {
448 python_initialized = false;
449 }
450 else
451 {
452 handle = LoadLibrary(python_path);
453 if (!handle)
454 {
455 python_initialized = false;
456 }
457 else
458 {
460 }
461 }
462
464 {
465
466 python_exec = LoadLibrary("python.exe");
467
468 if (python_exec == NULL)
469 {
470 std::cout << "ERROR: No python installation found." << std::endl;
471 std::cout << " Set PATH to Python Installation or set RAD_PYTHON_PATH to the Python library" << std::endl;
472 python_initialized = false;
473 return;
474 }
475
476 char python_filename[2048];
477 DWORD filelen = GetModuleFileName(python_exec, python_filename, 2048);
478 int i = filelen;
479 while (i > 0 && python_filename[i - 1] != '\\')
480 --i;
481 python_filename[i] = '\0';
482
483 strcpy_s(python_path, 20000, python_filename);
484 FreeLibrary(python_exec);
485
486 std::string dir_path = std::string(python_path);
487
488 WIN32_FIND_DATA find_file_data;
489 HANDLE hFind = FindFirstFile((dir_path + "python*.dll").c_str(), &find_file_data);
490
491 if (hFind == INVALID_HANDLE_VALUE)
492 {
493 std::cout << "ERROR: Could not find any python*.dll files in " << dir_path << std::endl;
494 python_initialized = false;
495 return;
496 }
497
498 do
499 {
500 std::string full_dll_path = dir_path + find_file_data.cFileName;
501 handle = LoadLibrary(full_dll_path.c_str());
502
503 if (handle)
504 {
505 python_initialized = true;
506 // std::cout << "Trying python library: " << full_dll_path << std::endl;
509 {
510 // std::cout << "Python library found at " << full_dll_path << std::endl;
511 FindClose(hFind);
513 return;
514 }
515 FreeLibrary(handle);
516 }
517 } while (FindNextFile(hFind, &find_file_data) != 0);
518 FindClose(hFind);
519 }
520 else
521 {
523 }
524}
525
526#else
527
528// Linux only: try to load the python library at the specified path
529bool try_load_library(const std::string &path)
530{
531 bool python_initialized = false;
532 handle = dlopen(path.c_str(), RTLD_LAZY |RTLD_GLOBAL);
533 if (handle)
534 {
535 std::cout << "Trying python library: " << path << std::endl;
538 {
539 std::cout << "INFO: Python library found at " << path << std::endl;
541 if (!My_IsInitialized())
542 {
543 std::cout << "ERROR: My_Initialize failed" << std::endl;
544 python_initialized = false;
545 }
546 }
547 }
548 return python_initialized;
549}
550
552{
553 python_initialized = false;
554 handle = nullptr;
555 // clear the previous errors in dlerror:
556 dlerror();
557 // Get the string from the environment variable RAD_PYTHON_PATH
558 const char *python_path = getenv("RAD_PYTHON_PATH");
559 if (python_path == nullptr)
560 {
561 python_initialized = false;
562 }
563 else
564 {
566 }
567
568 // if RAD_PYTHON_PATH was not found, or if the library was not loaded, try find PYTHONHOME
570 {
571 python_path = getenv("PYTHONHOME");
572 if (python_path)
573 {
574 std::cout << "INFO: searching for python library in PYTHONHOME" << std::endl;
575 std::vector<std::string> possible_dirs = {"/lib64/", "/lib/", "/usr/lib64/", "/usr/lib/", "/usr/lib/x86_64-linux-gnu/"};
576 for (const auto &dir : possible_dirs)
577 {
578 std::string dir_path = std::string(python_path) + dir;
579 DIR *d = opendir(dir_path.c_str());
580 if (d)
581 {
582 struct dirent *entry;
583 while ((entry = readdir(d)) != nullptr)
584 {
585 std::string filename(entry->d_name);
586 if (filename.find("libpython") == 0 && filename.find(".so") != std::string::npos)
587 {
588 python_initialized = try_load_library(dir_path + filename);
590 {
591 closedir(d);
592 return;
593 }
594 }
595 }
596 closedir(d);
597 }
598 }
599 }
600 }
601 // if we reach this point, we did not find any python library
602 // we look into some default locations
603 std::cout << " INFO: searching for python library in default locations LD_LIBRARY_PATH" << std::endl;
604 std::vector<std::string> possible_names = {
605 "libpython3.12.so",
606 "libpython3.11.so",
607 "libpython3.10.so",
608 "libpython3.9.so",
609 "libpython3.8.so",
610 "libpython3.7.so",
611 "libpython3.6.so",
612 "libpython3.5.so",
613 "libpython3.4.so",
614 "libpython3.3.so",
615 "libpython3.2.so",
616 "libpython3.1.so",
617 "libpython3.so",
618 "libpython3.0.so",
619 "libpython2.7.so"};
620 for (const auto &name : possible_names)
621 {
622 std::string libname = name;
625 {
626 return;
627 }
628 }
629}
630#endif
631
632
633// C++ functions that can be called from Fortran
634extern "C"
635{
636 void cpp_python_initialize(int *ierror)
637 {
639 { // already initialized
640 return;
641 }
642 // if ierror = 1 on entry, then "-python" is missing from the starter command line, and we will not execute any python code
643 if (*ierror == 1)
644 return;
645 *ierror = 1;
646 // Load Python dynamic library
649 {
650 pDict = MyModule_GetDict(MyImport_AddModule("__main__")); // Get the main module dictionary
651 if (!pDict)
652 {
653 std::cout << "ERROR in Python: fetching main module dictionary" << std::endl;
654 return;
655 }
656 int result = MyRun_SimpleString("import math"); // Import the math module for sin and other functions
657 if (result != 0)
658 {
659 std::cerr << "ERROR: Failed to import math module in Python." << std::endl;
660 // Print Python error traceback
661 if (MyErr_Occurred())
662 {
663 // Fetch the error details
664 PyObject *pType, *pValue, *pTraceback;
665 MyErr_Fetch(&pType, &pValue, &pTraceback);
666 if (pType)
667 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
668 if (pValue)
669 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
670 if (pTraceback)
671 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
672
673 // Print the error
674 //MyErr_Display(pType, pValue, pTraceback);
675
676 // Decrement reference counts for error objects
677 My_DecRef(pType);
678 My_DecRef(pValue);
679 My_DecRef(pTraceback);
680 exit_with_message("ERROR: Python function failed");
681 }
682 }else
683 {
684 *ierror = 0;
685 }
686 check_error(__LINE__);
687 }
688 }
690 {
692 {
693 return;
694 }
695 check_error(__LINE__);
696 const char *code =
697 "if 'initialize_environment' in globals():\n"
698 " initialize_environment()\n";
699 int result = MyRun_SimpleString(code);
700 check_error(__LINE__);
701 }
702
703 void cpp_python_sync(void* pcontext)
704 {
705
706 //std::cout<<"[PYTHON] cpp_python_sync called"<<std::endl;
708 {
709 return;
710 }
711 check_error(__LINE__);
712
713 // cast the context to a double pointer as a PyObject
714 char func_name[100];
715 // func_name = "sync"
716 func_name[0] = 's';
717 func_name[1] = 'y';
718 func_name[2] = 'n';
719 func_name[3] = 'c';
720 func_name[4] = '\0';
721 //std::cout<<"[PYTHON] cpp_python_sync called with function name: "<<func_name<<std::endl;
722
723 PyObject *context = static_cast<PyObject *>(pcontext);
724 PyObject* args = MyTuple_New(1);
725 if(!args)
726 {
727 std::cout << "ERROR: Failed to create Python tuple." << std::endl;
728 }
729 My_IncRef(context);
730 MyTuple_SetItem(args, 0, context); // This steals the reference
731 PyObject *pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, func_name));
732 if (!pFunc)
733 {
734 std::cout << "ERROR: Python function not found: " << func_name << std::endl;
735 My_DecRef(args);
736 }
737
738 if (!MyCallable_Check(pFunc)) {
739 std::cerr << "[PYTHON] Error: '" << func_name << "' is not callable" << std::endl;
740 My_DecRef(args);
741 }
742
743 PyObject* result = MyObject_CallObject(pFunc, args);
744 if (MyErr_Occurred())
745 {
746 // Fetch the error details
747 PyObject *pType, *pValue, *pTraceback;
748 MyErr_Fetch(&pType, &pValue, &pTraceback);
749 if (pType)
750 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pType)) << std::endl;
751 if (pValue)
752 std::cout << "[PYTHON] " << MyUnicode_AsUTF8(MyObject_Str(pValue)) << std::endl;
753 if (pTraceback)
754 std::cout << "[PYTHON]: " << MyUnicode_AsUTF8(MyObject_Str(pTraceback)) << std::endl;
755
756 // Decrement reference counts for error objects
757 My_DecRef(pType);
758 My_DecRef(pValue);
759 My_DecRef(pTraceback);
760 exit_with_message("ERROR: Python function failed");
761 }
762
763 My_DecRef(args);
764 check_error(__LINE__);
765
766 }
767
768
770 {
771 My_Finalize();
772 }
773 void cpp_python_execute_code(const char *code)
774 {
775 MyRun_SimpleString(code);
776 check_error(__LINE__);
777
778 }
779
781 {
783 {
784 return;
785 }
786 // initialize TIME and DT to 0
787 check_error(__LINE__);
788
789
790 PyObject *py_TIME = static_cast<PyObject *>(MyFloat_FromDouble(0.0));
791 PyObject *py_DT = static_cast<PyObject *>(MyFloat_FromDouble(0.0));
792 MyDict_SetItemString(pDict, "TIME", py_TIME);
793 MyDict_SetItemString(pDict, "DT", py_DT);
794
795 // loop over the set of nodes
796 for (auto node_uid : nodes_uid)
797 {
798 std::string entity_names[] = {"C", "D", "V", "A", "VR", "AR", "DR"};
799 for (auto name : entity_names)
800 {
801 const double x_values = static_cast<double>(1);
802 const double y_values = static_cast<double>(1);
803 const double z_values = static_cast<double>(1);
804 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
805 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
806 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
807 if (!py_x_values || !py_y_values || !py_z_values)
808 {
809 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
810 return;
811 }
812 std::string x_name = name + "X_" + std::to_string(node_uid);
813 std::string y_name = name + "Y_" + std::to_string(node_uid);
814 std::string z_name = name + "Z_" + std::to_string(node_uid);
815 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
816 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
817 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
818 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
819 // Release the Python objects
820 if (py_x_values != nullptr)
821 My_DecRef(py_x_values);
822 if (py_y_values != nullptr)
823 My_DecRef(py_y_values);
824 if (py_z_values != nullptr)
825 My_DecRef(py_z_values);
826 }
827 }
828 // Initialize all elements keywords to 1
829 for (auto p : element_variables)
830 {
831 double v = static_cast<double>(1);
832 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(v));
833 if (!py_value)
834 {
835 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
836 }
837 // convert p.second (const char *) to std::string
838 std::string keyword(p.second);
839 std::string sname = keyword + "_" + std::to_string(p.first);
840 MyDict_SetItemString(pDict, sname.c_str(), py_value);
841 if (py_value != nullptr)
842 My_DecRef(py_value);
843 }
844 check_error(__LINE__);
845
846 }
847
848 // register a function in the python dictionary
849 void cpp_python_register_function(char *name, char code[], int num_lines)
850 {
851 std::string tmp_string;
852 int current_line = 0;
853 std::stringstream function_code;
854
856 {
857 std::cout << "ERROR: Python not initialized" << std::endl;
858 std::cout << "Make sure that the following python code is safe" << std::endl;
859 std::cout << "and rerun the starter with the -python option." << std::endl;
860 }
861
862 for (int i = 0; current_line < num_lines;)
863 {
864 tmp_string.clear();
865 // Extract characters into the temporary string until a null character is found
866 while (code[i] != '\0')
867 {
868 tmp_string += code[i];
869 i++;
870 }
871 if (current_line == 0)
872 {
873 std::string function_name = extract_function_name(tmp_string);
874 if(function_name == "sync") sync_enabled = true;
875 if (function_name.empty())
876 {
877 std::cout << "ERROR: function name not found in function signature" << std::endl;
878 return;
879 }
880// copy function_name into argument name
881#ifdef _WIN64
882 strcpy_s(name, max_line_length, function_name.c_str());
883#else
884 strcpy(name, function_name.c_str());
885#endif
886 // add the null char at the end of the string
887 name[function_name.size()] = '\0';
888 }
889
890 const std::string s = parenthesis_to_underscore(tmp_string);
892
894 function_code << s << std::endl; // Add the line to the function code
895 i++; // Move past the null character
896 current_line++;
897 }
899 {
900 // initialize the global variables found in the python function
902 python_execute_code(function_code.str());
903 }
904 else
905 {
906 // print the python function to stdout and stderr
907 std::cout << function_code.str() << std::endl;
908 }
909 }
910
911 // works for functions with 2 arguments and 1 return value
912 void cpp_python_call_function(char *name, int num_args, double *args, int num_return, double *return_values)
913 {
915 {
916 return;
917 }
918 check_error(__LINE__);
919 // skip if name is initialize_environment
920 if (strcmp(name, "initialize_environment") == 0) return;
921 PyObject *result = call_python_function(name, args, num_args);
922 if (result)
923 {
924 return_values[0] = MyFloat_AsDouble(result);
925 My_DecRef(result);
926 } else
927 {
928 exit_with_message("ERROR: Python function failed");
929 }
930 check_error(__LINE__);
931 }
932
933 void cpp_python_call_function_with_state(char *name, double *return_values)
934 {
936 {
937 return;
938 }
939 check_error(__LINE__);
941 if (result)
942 {
943 *return_values = MyFloat_AsDouble(result);
944 My_DecRef(result);
945 } else {
946 exit_with_message("ERROR: Python function failed");
947 }
948 check_error(__LINE__);
949 }
950 // this function checks if a function exists in the python dictionary
951 void cpp_python_check_function(char *name, int *error)
952 {
953 PyObject *pFunc;
954 // std::cout << "Checking if function exists: " << name << std::endl;
956 {
957 pFunc = static_cast<PyObject *>(MyDict_GetItemString(pDict, name));
958 if (MyCallable_Check(pFunc))
959 {
960 *error = 0;
961 }
962 else
963 {
964 *error = 1;
965 }
966 }
967 else
968 {
969 *error = 1;
970 }
971
972 // std::cout << "Function exists? " << *error << std::endl;
973 }
974
975 void cpp_python_update_reals(char * basename, int * uid, my_real *reals, int num_reals)
976 {
977 // add BASENAME_$UID = reals[i] to the python dictionary
979 {
980 return;
981 }
982 check_error(__LINE__);
983 // Convert C++ doubles to Python objects
984 for (int i = 0; i < num_reals; i++)
985 {
986 double value = static_cast<double>(reals[i]);
987 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(value));
988 if (!py_value)
989 {
990 std::cerr << "ERROR: Failed to create Python object from C++ double." << std::endl;
991 return;
992 }
993 // Create the key in the format BASENAME_$UID
994 std::string key = std::string(basename) + "_" + std::to_string(uid[i]);
995 // Set the item in the Python dictionary
996 MyDict_SetItemString(pDict, key.c_str(), py_value);
997 // Release the Python object
998 My_DecRef(py_value);
999 }
1000 // Release the Python object
1001 check_error(__LINE__);
1002 }
1003
1005 {
1006 if (!python_initialized)
1007 {
1008 // std::cerr << "ERROR: Python is not initialized." << std::endl;
1009 return;
1010 }
1011
1012 check_error(__LINE__);
1013 if (!pDict)
1014 {
1015 std::cerr << "ERROR: Python main module dictionary not initialized." << std::endl;
1016 return;
1017 }
1018 // donvert TIME and DT to double precision in TIME2 and DT2
1019 double TIME2 = static_cast<double>(TIME);
1020 double DT2 = static_cast<double>(DT);
1021 // Convert C++ doubles to Python objects
1022 PyObject *py_TIME = static_cast<PyObject *>(MyFloat_FromDouble(TIME2));
1023 PyObject *py_DT = static_cast<PyObject *>(MyFloat_FromDouble(DT2));
1024
1025 if (!py_TIME || !py_DT)
1026 {
1027 std::cerr << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1028 return;
1029 }
1030
1031 // Set the Python global variables in the main module's dictionary
1032 MyDict_SetItemString(pDict, "TIME", py_TIME);
1033 MyDict_SetItemString(pDict, "DT", py_DT);
1034
1035 // Release the Python objects
1036 if (py_TIME != nullptr)
1037 My_DecRef(py_TIME);
1038 if (py_DT != nullptr)
1039 My_DecRef(py_DT);
1040 check_error(__LINE__);
1041
1042 }
1043 // return the number of nodes that are used in the python functions
1045 {
1046 if (!python_initialized)
1047 {
1048 *num_nodes = 0;
1049 }
1050 else
1051 {
1052 *num_nodes = nodes_uid.size();
1053 }
1054
1055 }
1056
1057 // return the list of nodes (user ids) that are used in the python functions
1058 void cpp_python_get_nodes(int *nodes_uid_array)
1059 {
1061 {
1062 int i = 0;
1063 for (auto node_uid : nodes_uid)
1064 {
1065 // std::cout << "Node uid: " << node_uid << std::endl;
1066 nodes_uid_array[i] = node_uid;
1067 i++;
1068 }
1069 }
1070 }
1071 // itab(i) = uid of node local node i
1072 void cpp_python_create_node_mapping(int *itab, int *num_nodes)
1073 {
1074 // print number of nodes and python_initialized
1075 // std::cout << "Number of nodes: " << *num_nodes << " python_initialized" << python_initialized << std::endl;
1077 {
1078 // loop over the set
1079 for (auto node_uid : nodes_uid)
1080 {
1081 // find i such that itab[i] = node_uid
1082 bool found = false;
1083 for (int i = 0; i < *num_nodes; i++)
1084 {
1085 if (itab[i] == node_uid)
1086 {
1087 nodes_uid_to_local_id[node_uid] = i;
1088 // std::cout << "Node uid: " << node_uid << " local id: " << i << std::endl;
1089 found = true;
1090 break;
1091 }
1092 }
1093 if (!found)
1094 {
1095 std::cout << "Node uid: " << node_uid << " not found in itab" << std::endl;
1096 }
1097 }
1098 check_error(__LINE__);
1099 }
1100 }
1101 // update the global variable sensors from the input arrays
1102 void cpp_python_update_sensors(int *types, int *uids, int *statuses, double *results, int *num_sensors)
1103 {
1104 //std::cout << "[PYTHON] update sensors" << std::endl;
1105 constexpr int sensor_python = 40; // PYTHON
1106 constexpr int sensor_energy = 14; // ENERGY
1107 constexpr int sensor_time = 0; // TIME
1108 constexpr int sensor_accel = 1; // ACCE
1109 constexpr int sensor_dist = 2; // DISP
1110 constexpr int sensor_sens = 3; // SENS
1111 constexpr int sensor_and = 4; // AND
1112 constexpr int sensor_or = 5; // OR
1113 constexpr int sensor_inter = 6; // INTER
1114 constexpr int sensor_rwall = 7; // RWALL
1115 constexpr int sensor_not = 8; // NOT
1116 constexpr int sensor_vel = 9; // VEL
1117 constexpr int sensor_gauge = 10; // GAUGE
1118 constexpr int sensor_rbody = 11; // RBODY
1119 constexpr int sensor_sect = 12; // SECT
1120 constexpr int sensor_work = 13; // WORK
1121 constexpr int sensor_dist_surf = 15; // DIST_SURF
1122 constexpr int sensor_hic = 16; // HIC
1123 constexpr int sensor_temp = 17; // TEMP
1124 // create a python dictionary with associating type to name
1125 const std::map<int, std::string> sensor_type_to_name = {
1126 {sensor_python, "PYTHON"},
1127 {sensor_energy, "ENERGY"},
1128 {sensor_time, "TIME"},
1129 {sensor_accel, "ACCE"},
1130 {sensor_dist, "DIST"},
1131 {sensor_sens, "SENS"},
1132 {sensor_and, "AND"},
1133 {sensor_or, "OR"},
1134 {sensor_inter, "INTER"},
1135 {sensor_rwall, "RWALL"},
1136 {sensor_not, "NOT"},
1137 {sensor_vel, "VEL"},
1138 {sensor_gauge, "GAUGE"},
1139 {sensor_rbody, "RBODY"},
1140 {sensor_sect, "SECT"},
1141 {sensor_work, "WORK"},
1142 {sensor_dist_surf, "DIST_SURF"},
1143 {sensor_hic, "HIC"},
1144 {sensor_temp, "TEMP"}};
1145
1146 if (!python_initialized)
1147 {
1148 return;
1149 }
1150 check_error(__LINE__);
1151 std::ostringstream oss;
1152 oss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::hexfloat;
1153 oss << "sensors = { \n";
1154 for (int i = 0; i < *num_sensors; i++)
1155 {
1156 int type = types[i];
1157 int uid = uids[i];
1158 int status = statuses[i];
1159 oss << " " << uid << " : { 'type' : '" << sensor_type_to_name.at(type) << "', 'status' : " << status;
1160 // depending on the type, the results are different
1161 if (type == sensor_energy)
1162 { // Eint = results[2*(i-1)], Ekin = results[2*(i-1)+1]
1163 oss << ", 'Eint' : float.fromhex('" << results[2 * i] << "'), 'Ekin' : float.fromhex('" << results[2 * i + 1] << "') ";
1164 }
1165 else if (type == sensor_inter || type == sensor_rwall)
1166 { // Force = results[2*(i-1)]
1167 oss << ", 'Force' : float.fromhex('" << results[2 * i] << "') ";
1168 }
1169 else if (type == sensor_dist || type == sensor_dist_surf)
1170 {
1171 oss << ", 'Distance' : float.fromhex('" << results[2 * i] << "') ";
1172 }
1173 else if (type == sensor_gauge)
1174 {
1175 oss << ", 'Pressure' : float.fromhex('" << results[2 * i] << "') ";
1176 }
1177 if (i < *num_sensors - 1)
1178 {
1179 oss << "},\n";
1180 }
1181 else
1182 {
1183 oss << "}\n";
1184 }
1185 }
1186 oss << "\n}";
1187
1188 std::string code = oss.str();
1189 // std::cout<< "Generated code: "<<code<<std::endl;
1190 python_execute_code(code);
1191 // check for errors
1192 check_error(__LINE__);
1193
1194 }
1195
1196 // values is an array of size (3*numnod) containing the values of the nodal entities
1197// call python_update_active_node_values(name_len, temp_name, val)
1198
1199 void cpp_python_update_active_node(int name_len, char *name, double *values)
1200 {
1201 if (!python_initialized)
1202 {
1203 return;
1204 }
1205 check_error(__LINE__);
1206 double x_values, y_values, z_values;
1207 // loop over the map nodes_uid_to_local_id
1208 {
1209 x_values = static_cast<double>(values[0]);
1210 y_values = static_cast<double>(values[1]);
1211 z_values = static_cast<double>(values[2]);
1212 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
1213 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
1214 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
1215 if (!py_x_values || !py_y_values || !py_z_values)
1216 {
1217 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1218 return;
1219 }
1220 // Set the Python global variables in the main module's dictionary
1221 std::string x_name = std::string(name) + "X_ACTIVE_NODE";
1222 std::string y_name = std::string(name) + "Y_ACTIVE_NODE";
1223 std::string z_name = std::string(name) + "Z_ACTIVE_NODE";
1224 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
1225 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
1226 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
1227 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
1228 // Release the Python objects
1229 if (py_x_values != nullptr)
1230 My_DecRef(py_x_values);
1231 if (py_y_values != nullptr)
1232 My_DecRef(py_y_values);
1233 if (py_z_values != nullptr)
1234 My_DecRef(py_z_values);
1235 check_error(__LINE__);
1236
1237 }
1238 }
1240 { // set ACTIVE_NODE as id, and ACTIVE_NODE_UID as uid
1241 if (!python_initialized)
1242 {
1243 return;
1244 }
1245 check_error(__LINE__);
1246 // Set the Python global variables in the main module's dictionary
1247 std::string id_name = "ACTIVE_NODE";
1248 std::string uid_name = "ACTIVE_NODE_UID";
1249 MyDict_SetItemString(pDict, id_name.c_str(), static_cast<PyObject *>(MyLong_FromLong(static_cast<long>(id))));
1250 MyDict_SetItemString(pDict, uid_name.c_str(), static_cast<PyObject *>(MyLong_FromLong(static_cast<long>(uid))));
1251 check_error(__LINE__);
1252
1253 }
1254
1255
1256 // values is an array of size (3*numnod) containing the values of the nodal entities
1257 void cpp_python_update_nodal_entity(int numnod, int name_len, char *name, my_real *values)
1258 {
1259 if (!python_initialized)
1260 {
1261 return;
1262 }
1263
1264 check_error(__LINE__);
1265 double x_values, y_values, z_values;
1266 // loop over the map nodes_uid_to_local_id
1267 for (auto it = nodes_uid_to_local_id.begin(); it != nodes_uid_to_local_id.end(); ++it)
1268 {
1269 int node_uid = it->first;
1270 int local_id = it->second;
1271 if(local_id > numnod-1)
1272 {
1273 std::cout << "ERROR: local_id " << local_id << " is greater than numnod " << numnod << std::endl;
1274 return;
1275 }
1276 x_values = static_cast<double>(values[3 * local_id]);
1277 y_values = static_cast<double>(values[3 * local_id + 1]);
1278 z_values = static_cast<double>(values[3 * local_id + 2]);
1279 PyObject *py_x_values = static_cast<PyObject *>(MyFloat_FromDouble(x_values));
1280 PyObject *py_y_values = static_cast<PyObject *>(MyFloat_FromDouble(y_values));
1281 PyObject *py_z_values = static_cast<PyObject *>(MyFloat_FromDouble(z_values));
1282 if (!py_x_values || !py_y_values || !py_z_values)
1283 {
1284 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1285 return;
1286 }
1287 // Set the Python global variables in the main module's dictionary
1288 std::string x_name = std::string(name) + "X_" + std::to_string(node_uid);
1289 std::string y_name = std::string(name) + "Y_" + std::to_string(node_uid);
1290 std::string z_name = std::string(name) + "Z_" + std::to_string(node_uid);
1291 // std::cout<<" write to python: "<<x_name<<" "<<y_name<<" "<<z_name<<std::endl;
1292 MyDict_SetItemString(pDict, x_name.c_str(), py_x_values);
1293 MyDict_SetItemString(pDict, y_name.c_str(), py_y_values);
1294 MyDict_SetItemString(pDict, z_name.c_str(), py_z_values);
1295 // Release the Python objects
1296 if (py_x_values != nullptr)
1297 My_DecRef(py_x_values);
1298 if (py_y_values != nullptr)
1299 My_DecRef(py_y_values);
1300 if (py_z_values != nullptr)
1301 My_DecRef(py_z_values);
1302
1303 check_error(__LINE__);
1304 }
1305 }
1306
1307 // update values for elemental entities found in the Python function
1308 void cpp_python_update_elemental_entity(char *name, double value, int uid)
1309 {
1310 double v = static_cast<double>(value);
1311 check_error(__LINE__);
1312 PyObject *py_value = static_cast<PyObject *>(MyFloat_FromDouble(v));
1313 if (!py_value)
1314 {
1315 std::cout << "ERROR: Failed to create Python objects from C++ doubles." << std::endl;
1316 }
1317 std::string sname = std::string(name) + "_" + std::to_string(uid);
1318 // std::cout<<"[PYTHON] update elemental entity: "<<sname<<" value: "<<v<<std::endl;
1319 MyDict_SetItemString(pDict, sname.c_str(), py_value);
1320 if (py_value != nullptr)
1321 My_DecRef(py_value);
1322 check_error(__LINE__);
1323 }
1324
1325 // return the size of the KeywordPairs element_variables
1327 {
1328 *nb = element_variables.size();
1329 }
1330
1331 void cpp_python_get_elemental_entity(int nb, char *name, int *uid)
1332 {
1333 size_t n = static_cast<size_t>(nb - 1);
1335 for (int i = 0; i < max_variable_length; i++)
1336 {
1337 name[i] = '\0';
1338 }
1339 // copy user id
1340 *uid = p.first;
1341 // copy variable name
1342#ifdef _WIN64
1343 strcpy_s(name, max_variable_length, p.second);
1344#else
1345 strcpy(name, p.second);
1346#endif
1347 }
1348
1349 void cpp_python_sample_function(char *name, my_real *x, my_real *y, int n)
1350 {
1351 //write the name
1352 constexpr size_t N = 10000; // Number of points
1353 double x_max = 1e+6;
1354 std::vector<double> Xtmp = initial_sampling(x_max,N);
1355 std::vector<double> X(2*N, 0.0);
1356 double scale = x_max / N;
1357
1358 // X = -Xtmp(N) .. -Xtmp(1) Xtmp(1) .. Xtmp(N)
1359 for (size_t i = 0; i < N; i++)
1360 {
1361 X[i] = -scale * Xtmp[N - i - 1];
1362 }
1363 for (size_t i = 0; i < N; i++)
1364 {
1365 X[i + N] = scale * Xtmp[i];
1366 }
1367 // I would like to symmetrically sample the function around 0, so I will sample the function at -X and X
1368 //Y of size N, filled with 0
1369 std::vector<double> Y(X.size(), 0.0);
1370 // evaluate the function at all X values using cpp_
1372 //Sample the function to get n points:
1373 std::vector<double> new_x = select_points(X,Y,size_t(n));
1374 std::vector<double> new_y(n, 0.0);
1375 call_python_function1D_vectors(name, new_x, new_y);
1376 //sizes:
1377 // copy the values to the output arrays
1378 for (int i = 0; i < n; i++)
1379 {
1380 x[i] = static_cast<my_real>(new_x[i]);
1381 y[i] = static_cast<my_real>(new_y[i]);
1382 }
1383 }
1384
1385
1386//
1387// subroutine python_add_ints_to_dict(context, name, len_name, values, nvalues) &
1388// bind(c, name="cpp_python_add_ints_to_dict")
1389// use iso_c_binding
1390// type(c_ptr), value, intent(in) :: context
1391// integer(kind=c_int), value, intent(in) :: nvalues
1392// character(kind=c_char), dimension(len_name), intent(in) :: name
1393// integer(kind=c_int), dimension(nvalues), intent(in) :: values
1394// end subroutine python_add_ints_to_dict
1395 //subroutine python_add_doubles_to_dict(context, name, len_name, values, nvalues) &
1396void cpp_python_add_ints_to_dict(void* context_ptr, const char* name, int len_name, int* values, int nvalues)
1397{ // expose the array without copying
1398 if (!python_initialized)
1399 {
1400 return;
1401 }
1402 check_error(__LINE__);
1403 PyObject * context = static_cast<PyObject*>(context_ptr);
1404 char ptr_key[100],size_key[100],type_key[100];
1405 snprintf(ptr_key, sizeof(ptr_key), "%s_ptr", name);
1406 snprintf(size_key, sizeof(size_key), "%s_size", name);
1407 snprintf(type_key, sizeof(type_key), "%s_type", name);
1408 PyObject* ptr_value = MyLong_FromVoidPtr(values);
1409 PyObject* size_value = MyLong_FromLong(static_cast<long>(nvalues));
1410 PyObject* type_value = MyUnicode_FromString("int");
1411
1412 // set the values in the context dictionary
1413 MyDict_SetItemString(context, ptr_key, ptr_value);
1414 MyDict_SetItemString(context, size_key, size_value);
1415 MyDict_SetItemString(context, type_key, type_value);
1416
1417 // release the references
1418 My_DecRef(ptr_value);
1419 My_DecRef(size_value);
1420 My_DecRef(type_value);
1421 check_error(__LINE__);
1422
1423}
1424
1425void cpp_python_add_doubles_to_dict(void* context_ptr, const char* name, int len_name, double* values, int nvalues)
1426{ // expose the array without copying
1427 if (!python_initialized)
1428 {
1429 return;
1430 }
1431 check_error(__LINE__);
1432 PyObject * context = static_cast<PyObject*>(context_ptr);
1433 char ptr_key[100],size_key[100],type_key[100];
1434 snprintf(ptr_key, sizeof(ptr_key), "%s_ptr", name);
1435 snprintf(size_key, sizeof(size_key), "%s_size", name);
1436 snprintf(type_key, sizeof(type_key), "%s_type", name);
1437 PyObject* ptr_value = MyLong_FromVoidPtr(values);
1438 PyObject* size_value = MyLong_FromLong(static_cast<long>(nvalues));
1439 PyObject* type_value = MyUnicode_FromString("double");
1440 // set the values in the context dictionary
1441 MyDict_SetItemString(context, ptr_key, ptr_value);
1442 MyDict_SetItemString(context, size_key, size_value);
1443 MyDict_SetItemString(context, type_key, type_value);
1444 // release the references
1445 My_DecRef(ptr_value);
1446 My_DecRef(size_value);
1447 My_DecRef(type_value);
1448 check_error(__LINE__);
1449}
1450 // set the values in the context dictionary
1451
1452
1454 check_error(__LINE__);
1455 PyObject* context = MyDict_New();
1456 if (!context) {
1457 return NULL;
1458 }
1459 return context;
1460 check_error(__LINE__);
1461}
1462
1463void cpp_python_free_context(void* context) {
1464 if (context) {
1465 My_DecRef(static_cast<PyObject*>(context));
1466 }
1467}
1468
1469} // extern "C"
1470
1471#else
1472// dummy functions
1473extern "C"
1474{
1475 void cpp_python_initialize(int *ok)
1476 {
1477 // ok = 0; if not ok
1478 *ok = 0;
1479 // std::cout << "ERROR: python not enabled" << std::endl;
1480 }
1481 void cpp_python_finalize()
1482 {
1483 // std::cout << "ERROR: python not enabled" << std::endl;
1484 }
1485 void cpp_python_execute_code(const char *code)
1486 {
1487 // std::cout << "ERROR: python not enabled" << std::endl;
1488 }
1489 void cpp_python_register_function(char *name, char code[500][1000], int num_lines)
1490 {
1491 // std::cout << "ERROR: python not enabled" << std::endl;
1492 }
1493 void cpp_python_call_function(char *name, int num_args, double *args, int num_return, double *return_values)
1494 {
1495 std::cout << "ERROR: python not enabled" << std::endl;
1496 }
1497 void cpp_python_sample_function(char *name, my_real *x, my_real *y, int n)
1498 {
1499 std::cout << "ERROR: python not enabled" << std::endl;
1500 }
1502 {
1503 std::cout << "ERROR: python not enabled" << std::endl;
1504 }
1505 void cpp_python_check_function(char *name, int *error)
1506 {
1507 // std::cout << "ERROR: python not enabled" << std::endl;
1508 }
1509 void cpp_python_update_time(double TIME, double DT) {}
1510 void cpp_python_get_number_of_nodes(int *num_nodes) {}
1511 // return the list of nodes (user ids) that are used in the python functions
1512 void cpp_python_get_nodes(int *nodes_uid_array) {}
1513 void cpp_python_create_node_mapping(int *itab, int *num_nodes) {}
1514 void cpp_python_update_nodal_entity(int numnod, int name_len, char *name, my_real *values) {}
1515 void cpp_python_update_elemental_entity(char *name, my_real value, int uid) {}
1517 void cpp_python_get_elemental_entity(int nb, char *name, int *uid) {}
1519 void cpp_python_update_sensors(int types, int *uids, int *statuses, double *results, int *num_sensors){}
1520}
1521
1522#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 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
void cpp_python_sample_function(char *name, my_real *x, my_real *y, int n)
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_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)
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_PyModule_GetDict MyModule_GetDict
T_PyList_New MyList_New
T_PyErr_Display MyErr_Display
T_Py_DecRef My_DecRef
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_PyErr_Occurred MyErr_Occurred
T_Py_IsInitialized My_IsInitialized
T_Py_Initialize My_Initialize
#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
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