Skip to content

Commit

Permalink
Allow Delegator to delete Python rates
Browse files Browse the repository at this point in the history
  • Loading branch information
speth committed Sep 11, 2022
1 parent cd7b90f commit bcade68
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
14 changes: 14 additions & 0 deletions include/cantera/base/Delegator.h
Expand Up @@ -9,6 +9,7 @@
#include "cantera/base/global.h"
#include "cantera/base/ctexceptions.h"
#include <array>
#include <list>

namespace Cantera
{
Expand Down Expand Up @@ -100,6 +101,12 @@ namespace Cantera
class Delegator
{
public:
~Delegator() {
for (auto& func : m_cleanup_funcs) {
func();
}
}

//! Set delegates for member functions with the signature `void()`.
void setDelegate(const std::string& name, const std::function<void()>& func,
const std::string& when)
Expand Down Expand Up @@ -227,6 +234,10 @@ class Delegator
*m_funcs_sz_csr[name] = makeDelegate(func, when, m_base_sz_csr[name]);
}

void addCleanupFunc(const std::function<void()>& func) {
m_cleanup_funcs.push_back(func);
}

protected:
//! Install a function with the signature `void()` as being delegatable
void install(const std::string& name, std::function<void()>& target,
Expand Down Expand Up @@ -446,6 +457,9 @@ class Delegator
std::map<std::string,
std::function<size_t(const std::string&)>*> m_funcs_sz_csr;
//! @}

//! Cleanup functions to be called from the destructor
std::list<std::function<void()>> m_cleanup_funcs;
};

}
Expand Down
13 changes: 12 additions & 1 deletion src/extensions/PythonExtensionManager.cpp
Expand Up @@ -72,14 +72,25 @@ void PythonExtensionManager::registerRateBuilders(const string& extensionName)
"Got unparsable input from ct_getPythonExtensibleRateTypes:"
"\n'''{}\n'''", rateTypes);
}

string rateName = tokens[0];

// Create a function that constructs and links a C++ ReactionRateDelegator
// object and a Python ExtensibleRate object of a particular type, and register
// this as the builder for reactions of this type
auto builder = [rateName, extensionName](const AnyMap& params, const UnitStack& units) {
auto delegator = make_unique<ReactionRateDelegator>();
ct_addPythonExtensibleRate(delegator.get(), extensionName, rateName);
PyObject* extRate = ct_newPythonExtensibleRate(delegator.get(),
extensionName, rateName);
if (extRate == nullptr) {
throw CanteraError("PythonExtensionManager::registerRateBuilders",
"ct_newPythonExtensibleRate failed");
}

// Make the delegator responsible for eventually deleting the Python object
Py_IncRef(extRate);
delegator->addCleanupFunc([extRate]() { Py_DecRef(extRate); });

return delegator.release();
};
ReactionRateFactory::factory()->reg(tokens[1], builder);
Expand Down
9 changes: 4 additions & 5 deletions src/extensions/pythonExtensions.pyx
Expand Up @@ -40,13 +40,12 @@ cdef public char* ct_getPythonExtensibleRateTypes(const string& module_name) exc
return c_string


cdef public int ct_addPythonExtensibleRate(CxxReactionRateDelegator* delegator,
const string& module_name,
const string& class_name) except -1:
cdef public object ct_newPythonExtensibleRate(CxxReactionRateDelegator* delegator,
const string& module_name,
const string& class_name):

mod = importlib.import_module(module_name.decode())
cdef ExtensibleRate rate = getattr(mod, class_name.decode())(init=False)
Py_INCREF(rate)
rate.set_cxx_object(delegator)
assign_delegates(rate, delegator)
return 0
return rate

0 comments on commit bcade68

Please sign in to comment.