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

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

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

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

◆ Module_Process()

void Module_Process ( ModuleSharedPtr  m)

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

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

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

338 {
339  // Create a module register helper, which will call the C++ function to
340  // create the module.
341  ModuleRegisterHelper *helper = new ModuleRegisterHelper(obj);
342 
343  // Register this with the module factory using std::bind to grab a function
344  // pointer to that particular object's function.
346  ModuleKey(modType, modName), std::bind(&ModuleRegisterHelper::create,
347  helper, std::placeholders::_1));
348 
349  // Create a capsule that will be embedded in the __main__ namespace. So
350  // deallocation will occur, but only once Python ends or the Python module
351  // is deallocated.
352  std::string modkey =
353  "_" + std::string(ModuleTypeMap[modType]) + "_" + modName;
354 
355 #if PY_MAJOR_VERSION == 2
356  py::object capsule(
357  py::handle<>(PyCObject_FromVoidPtr(helper, ModuleCapsuleDestructor)));
358 #else
359  py::object capsule(
360  py::handle<>(PyCapsule_New(helper, 0, ModuleCapsuleDestructor)));
361 #endif
362 
363  // Embed this in __main__.
364  py::import("__main__").attr(modkey.c_str()) = capsule;
365 }
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 261 of file Python/Module.cpp.

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

Referenced by export_Module().

◆ ModuleCapsuleDestructor()

void ModuleCapsuleDestructor ( PyObject *  ptr)

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

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

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

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