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)
 
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 409 of file Python/Module.cpp.

410 {
411  // Export ModuleType enum.
413 
414  // Define ModuleWrap to be implicitly convertible to a Module, since it
415  // seems that doesn't sometimes get picked up.
416  py::implicitly_convertible<std::shared_ptr<ModuleWrap<Module>>,
417  std::shared_ptr<Module>>();
418  py::implicitly_convertible<std::shared_ptr<ModuleWrap<InputModule>>,
419  std::shared_ptr<Module>>();
420  py::implicitly_convertible<std::shared_ptr<ModuleWrap<OutputModule>>,
421  std::shared_ptr<Module>>();
422  py::implicitly_convertible<std::shared_ptr<ModuleWrap<ProcessModule>>,
423  std::shared_ptr<Module>>();
424 
425  // Wrapper for the Module class. Note that since Module contains a pure
426  // virtual function, we need the ModuleWrap helper class to handle this for
427  // us. In the lightweight wrappers above, we therefore need to ensure we're
428  // passing std::shared_ptr<Module> as the first argument, otherwise they
429  // won't accept objects constructed from Python.
430  py::class_<ModuleWrap<Module>, std::shared_ptr<ModuleWrap<Module>>,
431  boost::noncopyable>("Module", py::init<FieldSharedPtr>())
432 
433  // Process function for this module.
434  .def("Process", py::pure_virtual(&Module_Process))
435  .def("Run", py::pure_virtual(&Module_Process))
436 
437  // Configuration options.
438  .def("RegisterConfig", Module_RegisterConfig,
439  (py::arg("key"), py::arg("value") = ""))
440  .def("PrintConfig", &Module::PrintConfig)
441  .def("SetDefaults", &Module::SetDefaults)
442  .def("GetStringConfig", Module_GetConfig<std::string>)
443  .def("GetFloatConfig", Module_GetConfig<double>)
444  .def("GetIntConfig", Module_GetConfig<int>)
445  .def("GetBoolConfig", Module_GetConfig<bool>)
446  .def("AddConfigOption", ModuleWrap_AddConfigOption<Module>,
447  (py::arg("key"), py::arg("defValue"), py::arg("desc"),
448  py::arg("isBool") = false))
449 
450  // Allow direct access to field object through a property.
451  .def_readwrite("field", &ModuleWrap<Module>::m_f)
452 
453  // Factory functions.
454  .def("Register", &Module_Register)
455  .staticmethod("Register");
456 
458 
459  PythonModuleClass<InputModule>("InputModule");
460  PythonModuleClass<ProcessModule>("ProcessModule");
461  PythonModuleClass<OutputModule>("OutputModule");
462 }
#define NEKPY_WRAP_ENUM_STRING(ENUMNAME, MAPNAME)
Definition: NekPyConfig.hpp:78
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...
const std::string ModuleTypeMap[]
Definition: Module.h:74
Module wrapper to handle virtual function calls in Module and its subclasses as defined by the templa...

References Module_Process(), Module_Register(), Module_RegisterConfig(), Nektar::FieldUtils::ModuleTypeMap, NEKPY_WRAP_ENUM_STRING, Nektar::FieldUtils::Module::PrintConfig(), and Nektar::FieldUtils::Module::SetDefaults().

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 165 of file Python/Module.cpp.

166 {
168 
170 
171  if (modType == eProcessModule && py::len(args) != 2)
172  {
173  throw NekError("ProcessModule.Create() requires two arguments: "
174  "module name and a Field object.");
175  }
176  else if (modType != eProcessModule && py::len(args) < 2)
177  {
178  throw NekError(ModuleTypeMap[modType] +
179  "Module.Create() requires "
180  "two arguments: module name and a Field object; "
181  "optionally a filename.");
182  }
183 
184  std::string modName = py::extract<std::string>(args[0]);
185  ModuleKey modKey = std::make_pair(modType, modName);
186 
187  if (!py::extract<FieldSharedPtr>(args[1]).check())
188  {
189  throw NekError("Second argument to Create() should be a Field object.");
190  }
191 
192  FieldSharedPtr field = py::extract<FieldSharedPtr>(args[1]);
193  ModuleSharedPtr mod = GetModuleFactory().CreateInstance(modKey, field);
194 
195  if (modType == eInputModule)
196  {
197  // For input modules we can try to interpret the remaining arguments as
198  // input files. Assume that the file's type is identical to the module
199  // name.
200  for (int i = 2; i < py::len(args); ++i)
201  {
202  std::string in_fname = py::extract<std::string>(args[i]);
203  mod->RegisterConfig("infile", in_fname);
204  mod->AddFile(modName, in_fname);
205  }
206  }
207  else if (modType == eOutputModule && py::len(args) >= 3)
208  {
209  // For output modules we can try to interpret the remaining argument as
210  // an output file.
211  mod->RegisterConfig("outfile", py::extract<std::string>(args[2]));
212  }
213 
214  // Process keyword arguments.
215  py::list items = kwargs.items();
216 
217  for (int i = 0; i < py::len(items); ++i)
218  {
219  std::string arg = py::extract<std::string>(items[i][0]);
220 
221  if (arg == "infile" && modKey.first == eInputModule)
222  {
223  py::extract<py::dict> dict_check(items[i][1]);
224 
225  if (!dict_check.check())
226  {
227  throw NekError("infile should be a dictionary.");
228  }
229 
230  py::dict ftype_fname_dict = py::extract<py::dict>(items[i][1]);
231  py::list ft_fn_items = ftype_fname_dict.items();
232  for (int i = 0; i < py::len(ft_fn_items); ++i)
233  {
234  std::string f_type =
235  py::extract<std::string>(ft_fn_items[i][0]);
236  std::string f_name = py::extract<std::string>(
237  ft_fn_items[i][1].attr("__str__")());
238  mod->RegisterConfig(arg, f_name);
239  mod->AddFile(f_type, f_name);
240  }
241  }
242  else
243  {
244  std::string val =
245  py::extract<std::string>(items[i][1].attr("__str__")());
246  mod->RegisterConfig(arg, val);
247  }
248  }
249 
250  mod->SetDefaults();
251 
252  return mod;
253 }
Nektar::ErrorUtil::NekError NekError
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:991
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
std::shared_ptr< Module > ModuleSharedPtr
Definition: Module.h:321
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49

References Nektar::LibUtilities::NekFactory< tKey, tBase, tParam >::CreateInstance(), Nektar::FieldUtils::eInputModule, Nektar::FieldUtils::eOutputModule, Nektar::FieldUtils::eProcessModule, 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 128 of file Python/Module.cpp.

129 {
130  return mod->GetConfigOption(key).as<T>();
131 }

◆ Module_Process()

void Module_Process ( ModuleSharedPtr  m)

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

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

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 337 of file Python/Module.cpp.

339 {
340  // Create a module register helper, which will call the C++ function to
341  // create the module.
342  ModuleRegisterHelper *helper = new ModuleRegisterHelper(obj);
343 
344  // Register this with the module factory using std::bind to grab a function
345  // pointer to that particular object's function.
347  ModuleKey(modType, modName), std::bind(&ModuleRegisterHelper::create,
348  helper, std::placeholders::_1));
349 
350  // Create a capsule that will be embedded in the __main__ namespace. So
351  // deallocation will occur, but only once Python ends or the Python module
352  // is deallocated.
353  std::string modkey =
354  "_" + std::string(ModuleTypeMap[modType]) + "_" + modName;
355 
356 #if PY_MAJOR_VERSION == 2
357  py::object capsule(
358  py::handle<>(PyCObject_FromVoidPtr(helper, ModuleCapsuleDestructor)));
359 #else
360  py::object capsule(
361  py::handle<>(PyCapsule_New(helper, 0, ModuleCapsuleDestructor)));
362 #endif
363 
364  // Embed this in __main__.
365  py::import("__main__").attr(modkey.c_str()) = capsule;
366 }
void ModuleCapsuleDestructor(PyObject *ptr)
ModuleSharedPtr create(FieldSharedPtr field)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198

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 262 of file Python/Module.cpp.

264 {
265  mod->RegisterConfig(key, value);
266 }

Referenced by export_Module().

◆ ModuleCapsuleDestructor()

void ModuleCapsuleDestructor ( PyObject *  ptr)

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

308 {
309  ModuleRegisterHelper *tmp =
310  (ModuleRegisterHelper *)PyCapsule_GetPointer(ptr, 0);
311  delete tmp;
312 }

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 269 of file Python/Module.cpp.

273 {
274  mod->AddConfigOption(key, defValue, desc, isBool);
275 }