Nektar++
Classes | Functions
Python/Module.cpp File Reference
#include <FieldUtils/Module.h>
#include <LibUtilities/Python/NekPyConfig.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/program_options.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 407 of file Python/Module.cpp.

408 {
409  // Export ModuleType enum.
411 
412  // Define ModuleWrap to be implicitly convertible to a Module, since it
413  // seems that doesn't sometimes get picked up.
414  py::implicitly_convertible<std::shared_ptr<ModuleWrap<Module>>,
415  std::shared_ptr<Module>>();
416  py::implicitly_convertible<std::shared_ptr<ModuleWrap<InputModule>>,
417  std::shared_ptr<Module>>();
418  py::implicitly_convertible<std::shared_ptr<ModuleWrap<OutputModule>>,
419  std::shared_ptr<Module>>();
420  py::implicitly_convertible<std::shared_ptr<ModuleWrap<ProcessModule>>,
421  std::shared_ptr<Module>>();
422 
423  // Wrapper for the Module class. Note that since Module contains a pure
424  // virtual function, we need the ModuleWrap helper class to handle this for
425  // us. In the lightweight wrappers above, we therefore need to ensure we're
426  // passing std::shared_ptr<Module> as the first argument, otherwise they
427  // won't accept objects constructed from Python.
428  py::class_<ModuleWrap<Module>, std::shared_ptr<ModuleWrap<Module>>,
429  boost::noncopyable>("Module", py::init<FieldSharedPtr>())
430 
431  // Process function for this module.
432  .def("Process", py::pure_virtual(&Module_Process))
433  .def("Run", py::pure_virtual(&Module_Process))
434 
435  // Configuration options.
436  .def("RegisterConfig", Module_RegisterConfig,
437  (py::arg("key"), py::arg("value") = ""))
438  .def("PrintConfig", &Module::PrintConfig)
439  .def("SetDefaults", &Module::SetDefaults)
440  .def("GetStringConfig", Module_GetConfig<std::string>)
441  .def("GetFloatConfig", Module_GetConfig<double>)
442  .def("GetIntConfig", Module_GetConfig<int>)
443  .def("GetBoolConfig", Module_GetConfig<bool>)
444  .def("AddConfigOption", ModuleWrap_AddConfigOption<Module>,
445  (py::arg("key"), py::arg("defValue"), py::arg("desc"),
446  py::arg("isBool") = false))
447 
448  // Allow direct access to field object through a property.
449  .def_readwrite("field", &ModuleWrap<Module>::m_f)
450 
451  // Factory functions.
452  .def("Register", &Module_Register)
453  .staticmethod("Register");
454 
456 
457  PythonModuleClass<InputModule>("InputModule");
458  PythonModuleClass<ProcessModule>("ProcessModule");
459  PythonModuleClass<OutputModule>("OutputModule");
460 }
#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] + "Module.Create() requires "
178  "two arguments: module name and a Field object; "
179  "optionally a filename.");
180  }
181 
182  std::string modName = py::extract<std::string>(args[0]);
183  ModuleKey modKey = std::make_pair(modType, modName);
184 
185  if (!py::extract<FieldSharedPtr>(args[1]).check())
186  {
187  throw NekError("Second argument to Create() should be a Field object.");
188  }
189 
190  FieldSharedPtr field = py::extract<FieldSharedPtr>(args[1]);
191  ModuleSharedPtr mod = GetModuleFactory().CreateInstance(modKey, field);
192 
193  if (modType == eInputModule)
194  {
195  // For input modules we can try to interpret the remaining arguments as
196  // input files. Assume that the file's type is identical to the module
197  // name.
198  for (int i = 2; i < py::len(args); ++i)
199  {
200  std::string in_fname = py::extract<std::string>(args[i]);
201  mod->RegisterConfig("infile", in_fname);
202  mod->AddFile(modName, in_fname);
203  }
204  }
205  else if (modType == eOutputModule && py::len(args) >= 3)
206  {
207  // For output modules we can try to interpret the remaining argument as
208  // an output file.
209  mod->RegisterConfig("outfile", py::extract<std::string>(args[2]));
210  }
211 
212  // Process keyword arguments.
213  py::list items = kwargs.items();
214 
215  for (int i = 0; i < py::len(items); ++i)
216  {
217  std::string arg = py::extract<std::string>(items[i][0]);
218 
219  if (arg == "infile" && modKey.first == eInputModule)
220  {
221  py::extract<py::dict> dict_check(items[i][1]);
222 
223  if (!dict_check.check())
224  {
225  throw NekError("infile should be a dictionary.");
226  }
227 
228  py::dict ftype_fname_dict = py::extract<py::dict>(items[i][1]);
229  py::list ft_fn_items = ftype_fname_dict.items();
230  for (int i = 0; i < py::len(ft_fn_items); ++i)
231  {
232  std::string f_type =
233  py::extract<std::string>(ft_fn_items[i][0]);
234  std::string f_name = py::extract<std::string>(
235  ft_fn_items[i][1].attr("__str__")());
236  mod->RegisterConfig(arg, f_name);
237  mod->AddFile(f_type, f_name);
238  }
239  }
240  else
241  {
242  std::string val =
243  py::extract<std::string>(items[i][1].attr("__str__")());
244  mod->RegisterConfig(arg, val);
245  }
246  }
247 
248  mod->SetDefaults();
249 
250  return mod;
251 }
Nektar::ErrorUtil::NekError NekError
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:145
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:989
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:290
std::shared_ptr< Module > ModuleSharedPtr
Definition: Module.h:294
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 335 of file Python/Module.cpp.

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

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

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

Referenced by export_Module().

◆ ModuleCapsuleDestructor()

void ModuleCapsuleDestructor ( PyObject *  ptr)

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

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

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

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