Nektar++
Classes | Functions
Python/Module.cpp File Reference
#include <FieldUtils/Module.h>
#include <LibUtilities/Python/NekPyConfig.hpp>
#include <boost/program_options.hpp>
#include <boost/python/raw_function.hpp>

Go to the source code of this file.

Classes

struct  ModuleWrap< MODTYPE >
 Module wrapper to handle virtual function calls in Module and its subclasses as defined by the template parameter. More...
 
struct  ModuleTypeProxy< MODTYPE >
 
struct  ModuleTypeProxy< InputModule >
 
struct  ModuleTypeProxy< ProcessModule >
 
struct  ModuleTypeProxy< OutputModule >
 
class  ModuleRegisterHelper
 
struct  ModuleWrapConverter< MODTYPE >
 
struct  PythonModuleClass< MODTYPE >
 

Functions

void Module_Process (ModuleSharedPtr m)
 
template<typename T >
Module_GetConfig (std::shared_ptr< Module > mod, const std::string &key)
 
void Module_GetVtkGrid (std::shared_ptr< Module > mod)
 
template<typename MODTYPE >
ModuleSharedPtr Module_Create (py::tuple args, py::dict kwargs)
 Lightweight wrapper for Module factory creation function. More...
 
void Module_RegisterConfig (std::shared_ptr< Module > mod, std::string const &key, std::string const &value)
 Lightweight wrapper for FieldUtils::Module::RegisterConfig. More...
 
template<typename MODTYPE >
void ModuleWrap_AddConfigOption (std::shared_ptr< ModuleWrap< MODTYPE > > mod, std::string const &key, std::string const &defValue, std::string const &desc, bool isBool)
 
void ModuleCapsuleDestructor (PyObject *ptr)
 
void Module_Register (ModuleType const &modType, std::string const &modName, py::object &obj)
 Lightweight wrapper for the Module factory RegisterCreatorFunction, to support the ability for Python subclasses of Module to register themselves with the Nektar++ Module factory. More...
 
void export_Module ()
 

Function Documentation

◆ export_Module()

void export_Module ( )

Definition at line 437 of file Python/Module.cpp.

438{
439 // Export ModuleType enum.
441
442#ifdef NEKTAR_USING_VTK
443 VTK_PYTHON_CONVERSION(vtkUnstructuredGrid);
444#endif
445
446 // Define ModuleWrap to be implicitly convertible to a Module, since it
447 // seems that doesn't sometimes get picked up.
448 py::implicitly_convertible<std::shared_ptr<ModuleWrap<Module>>,
449 std::shared_ptr<Module>>();
450 py::implicitly_convertible<std::shared_ptr<ModuleWrap<InputModule>>,
451 std::shared_ptr<Module>>();
452 py::implicitly_convertible<std::shared_ptr<ModuleWrap<OutputModule>>,
453 std::shared_ptr<Module>>();
454 py::implicitly_convertible<std::shared_ptr<ModuleWrap<ProcessModule>>,
455 std::shared_ptr<Module>>();
456
457 // Wrapper for the Module class. Note that since Module contains a pure
458 // virtual function, we need the ModuleWrap helper class to handle this for
459 // us. In the lightweight wrappers above, we therefore need to ensure we're
460 // passing std::shared_ptr<Module> as the first argument, otherwise they
461 // won't accept objects constructed from Python.
462 py::class_<ModuleWrap<Module>, std::shared_ptr<ModuleWrap<Module>>,
463 boost::noncopyable>("Module", py::init<FieldSharedPtr>())
464
465 // Process function for this module.
466 .def("Process", py::pure_virtual(&Module_Process))
467 .def("Run", py::pure_virtual(&Module_Process))
468
469 // Configuration options.
470 .def("RegisterConfig", Module_RegisterConfig,
471 (py::arg("key"), py::arg("value") = ""))
472 .def("PrintConfig", &Module::PrintConfig)
473 .def("SetDefaults", &Module::SetDefaults)
474 .def("GetStringConfig", Module_GetConfig<std::string>)
475 .def("GetFloatConfig", Module_GetConfig<double>)
476 .def("GetIntConfig", Module_GetConfig<int>)
477 .def("GetBoolConfig", Module_GetConfig<bool>)
478 .def("AddConfigOption", ModuleWrap_AddConfigOption<Module>,
479 (py::arg("key"), py::arg("defValue"), py::arg("desc"),
480 py::arg("isBool") = false))
481 .def("GetVtkGrid", Module_GetVtkGrid,
482 py::return_value_policy<py::return_by_value>())
483
484 // Allow direct access to field object through a property.
485 .def_readwrite("field", &ModuleWrap<Module>::m_f)
486
487 // Factory functions.
488 .def("Register", &Module_Register)
489 .staticmethod("Register");
490
492
493 PythonModuleClass<InputModule>("InputModule");
494 PythonModuleClass<ProcessModule>("ProcessModule");
495 PythonModuleClass<OutputModule>("OutputModule");
496}
#define NEKPY_WRAP_ENUM_STRING(ENUMNAME, MAPNAME)
Definition: NekPyConfig.hpp:80
void Module_RegisterConfig(std::shared_ptr< Module > mod, std::string const &key, std::string const &value)
Lightweight wrapper for FieldUtils::Module::RegisterConfig.
void Module_Process(ModuleSharedPtr m)
void Module_Register(ModuleType const &modType, std::string const &modName, py::object &obj)
Lightweight wrapper for the Module factory RegisterCreatorFunction, to support the ability for Python...
void Module_GetVtkGrid(std::shared_ptr< Module > mod)
#define VTK_PYTHON_CONVERSION(type)
Definition: VtkWrapper.hpp:145
const std::string ModuleTypeMap[]
Definition: Module.h:72
Module wrapper to handle virtual function calls in Module and its subclasses as defined by the templa...

References Module_GetVtkGrid(), Module_Process(), Module_Register(), Module_RegisterConfig(), Nektar::FieldUtils::ModuleTypeMap, NEKPY_WRAP_ENUM_STRING, and VTK_PYTHON_CONVERSION.

Referenced by BOOST_PYTHON_MODULE().

◆ Module_Create()

template<typename MODTYPE >
ModuleSharedPtr Module_Create ( py::tuple  args,
py::dict  kwargs 
)

Lightweight wrapper for Module factory creation function.

Parameters
modTypeModule type (input/process/output).
modNameModule name (typically filename extension).
fieldField that will be passed between modules.
Template Parameters
MODTYPESubclass of Module (e.g #InputModule, #OutputModule)

Definition at line 193 of file Python/Module.cpp.

194{
196
198
199 if (modType == eProcessModule && py::len(args) != 2)
200 {
201 throw NekError("ProcessModule.Create() requires two arguments: "
202 "module name and a Field object.");
203 }
204 else if (modType != eProcessModule && py::len(args) < 2)
205 {
206 throw NekError(ModuleTypeMap[modType] +
207 "Module.Create() requires "
208 "two arguments: module name and a Field object; "
209 "optionally a filename.");
210 }
211
212 std::string modName = py::extract<std::string>(args[0]);
213 ModuleKey modKey = std::make_pair(modType, modName);
214
215 if (!py::extract<FieldSharedPtr>(args[1]).check())
216 {
217 throw NekError("Second argument to Create() should be a Field object.");
218 }
219
220 FieldSharedPtr field = py::extract<FieldSharedPtr>(args[1]);
222
223 if (modType == eInputModule)
224 {
225 // For input modules we can try to interpret the remaining arguments as
226 // input files. Assume that the file's type is identical to the module
227 // name.
228 for (int i = 2; i < py::len(args); ++i)
229 {
230 std::string in_fname = py::extract<std::string>(args[i]);
231 mod->RegisterConfig("infile", in_fname);
232 mod->AddFile(modName, in_fname);
233 }
234 }
235 else if (modType == eOutputModule && py::len(args) >= 3)
236 {
237 // For output modules we can try to interpret the remaining argument as
238 // an output file.
239 mod->RegisterConfig("outfile", py::extract<std::string>(args[2]));
240 }
241
242 // Process keyword arguments.
243 py::list items = kwargs.items();
244
245 for (int i = 0; i < py::len(items); ++i)
246 {
247 std::string arg = py::extract<std::string>(items[i][0]);
248
249 if (arg == "infile" && modKey.first == eInputModule)
250 {
251 py::extract<py::dict> dict_check(items[i][1]);
252
253 if (!dict_check.check())
254 {
255 throw NekError("infile should be a dictionary.");
256 }
257
258 py::dict ftype_fname_dict = py::extract<py::dict>(items[i][1]);
259 py::list ft_fn_items = ftype_fname_dict.items();
260 for (int i = 0; i < py::len(ft_fn_items); ++i)
261 {
262 std::string f_type =
263 py::extract<std::string>(ft_fn_items[i][0]);
264 std::string f_name = py::extract<std::string>(
265 ft_fn_items[i][1].attr("__str__")());
266 mod->RegisterConfig(arg, f_name);
267 mod->AddFile(f_type, f_name);
268 }
269 }
270 else
271 {
272 std::string val =
273 py::extract<std::string>(items[i][1].attr("__str__")());
274 mod->RegisterConfig(arg, val);
275 }
276 }
277
278 mod->SetDefaults();
279
280 return mod;
281}
Nektar::ErrorUtil::NekError NekError
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:1026
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:180
std::shared_ptr< Module > ModuleSharedPtr
Definition: Module.h:329
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:47

References Nektar::LibUtilities::NekFactory< tKey, tBase, tParam >::CreateInstance(), Nektar::FieldUtils::eInputModule, Nektar::FieldUtils::eOutputModule, Nektar::FieldUtils::eProcessModule, FilterPython_Function::field, Nektar::FieldUtils::GetModuleFactory(), and Nektar::FieldUtils::ModuleTypeMap.

◆ Module_GetConfig()

template<typename T >
T Module_GetConfig ( std::shared_ptr< Module mod,
const std::string &  key 
)

Definition at line 132 of file Python/Module.cpp.

133{
134 return mod->GetConfigOption(key).as<T>();
135}

◆ Module_GetVtkGrid()

void Module_GetVtkGrid ( std::shared_ptr< Module mod)

Definition at line 177 of file Python/Module.cpp.

178{
180 throw NekError("Nektar++ has not been compiled with VTK support.");
181}

Referenced by export_Module().

◆ Module_Process()

void Module_Process ( ModuleSharedPtr  m)

Definition at line 106 of file Python/Module.cpp.

107{
108 if (m->m_f->m_nParts > 1)
109 {
110 if (m->GetModulePriority() == eOutput)
111 {
112 m->m_f->m_comm = m->m_f->m_partComm;
113 if (m->GetModuleName() != "OutputInfo")
114 {
115 m->RegisterConfig("writemultiplefiles");
116 }
117 }
118 else if (m->GetModulePriority() == eCreateGraph)
119 {
120 m->m_f->m_comm = m->m_f->m_partComm;
121 }
122 else
123 {
124 m->m_f->m_comm = m->m_f->m_defComm;
125 }
126 }
127 m->SetDefaults();
128 m->Process(m->m_f->m_vm);
129}

References Nektar::FieldUtils::eCreateGraph, and Nektar::FieldUtils::eOutput.

Referenced by export_Module(), and PythonModuleClass< MODTYPE >::PythonModuleClass().

◆ Module_Register()

void Module_Register ( ModuleType const &  modType,
std::string const &  modName,
py::object &  obj 
)

Lightweight wrapper for the Module factory RegisterCreatorFunction, to support the ability for Python subclasses of Module to register themselves with the Nektar++ Module factory.

This function wraps the NekFactory RegisterCreatorFunction. This function expects a function pointer to a C++ object that will construct a Module. In this case we therefore need to construct a function call that will construct our Python object (which is a subclass of Module), and then pass this back to Boost.Python to give the Python object back.

We have to do some indirection here to get this to work, but we can achieve this with the following strategy:

  • Create a ModuleRegisterHelper object, which as an argument will store the Python class instance that will be instantiated from the Python side.
  • Using std::bind, construct a function pointer to the helper's creation function, ModuleRegisterHelper::create.
  • Create a Python capsule that will contain the ModuleRegisterHelper instance, and register this in the global namespace of the current module. This then ties the capsule to the lifetime of the module.

Definition at line 365 of file Python/Module.cpp.

367{
368 // Create a module register helper, which will call the C++ function to
369 // create the module.
371
372 // Register this with the module factory using std::bind to grab a function
373 // pointer to that particular object's function.
375 ModuleKey(modType, modName), std::bind(&ModuleRegisterHelper::create,
376 helper, std::placeholders::_1));
377
378 // Create a capsule that will be embedded in the __main__ namespace. So
379 // deallocation will occur, but only once Python ends or the Python module
380 // is deallocated.
381 std::string modkey =
382 "_" + std::string(ModuleTypeMap[modType]) + "_" + modName;
383
384#if PY_MAJOR_VERSION == 2
385 py::object capsule(
386 py::handle<>(PyCObject_FromVoidPtr(helper, ModuleCapsuleDestructor)));
387#else
388 py::object capsule(
389 py::handle<>(PyCapsule_New(helper, nullptr, ModuleCapsuleDestructor)));
390#endif
391
392 // Embed this in __main__.
393 py::import("__main__").attr(modkey.c_str()) = capsule;
394}
void ModuleCapsuleDestructor(PyObject *ptr)
ModuleSharedPtr create(FieldSharedPtr field)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.

References ModuleRegisterHelper::create(), Nektar::FieldUtils::GetModuleFactory(), ModuleCapsuleDestructor(), Nektar::FieldUtils::ModuleTypeMap, and Nektar::LibUtilities::NekFactory< tKey, tBase, tParam >::RegisterCreatorFunction().

Referenced by export_Module().

◆ Module_RegisterConfig()

void Module_RegisterConfig ( std::shared_ptr< Module mod,
std::string const &  key,
std::string const &  value 
)

Lightweight wrapper for FieldUtils::Module::RegisterConfig.

Parameters
modModule to call
keyConfiguration key.
valueOptional value (some configuration options are boolean).

Definition at line 290 of file Python/Module.cpp.

292{
293 mod->RegisterConfig(key, value);
294}

Referenced by export_Module().

◆ ModuleCapsuleDestructor()

void ModuleCapsuleDestructor ( PyObject *  ptr)

Definition at line 335 of file Python/Module.cpp.

336{
338 (ModuleRegisterHelper *)PyCapsule_GetPointer(ptr, nullptr);
339 delete tmp;
340}

Referenced by Module_Register().

◆ ModuleWrap_AddConfigOption()

template<typename MODTYPE >
void ModuleWrap_AddConfigOption ( std::shared_ptr< ModuleWrap< MODTYPE > >  mod,
std::string const &  key,
std::string const &  defValue,
std::string const &  desc,
bool  isBool 
)

Definition at line 297 of file Python/Module.cpp.

301{
302 mod->AddConfigOption(key, defValue, desc, isBool);
303}