Test ExtensibleRate memory management

This commit is contained in:
Ray Speth 2022-12-14 16:59:15 -05:00 committed by Ingmar Schoegl
parent 5e5e7dfd23
commit 19d55aa426
2 changed files with 39 additions and 0 deletions

View File

@ -2,6 +2,7 @@ from math import exp
from pathlib import Path from pathlib import Path
import sys import sys
import textwrap import textwrap
import gc
import cantera as ct import cantera as ct
import numpy as np import numpy as np
@ -1619,6 +1620,29 @@ class TestExtensible2(utilities.CanteraTest):
with pytest.raises(ct.CanteraError, match="SyntaxError"): with pytest.raises(ct.CanteraError, match="SyntaxError"):
ct.Solution(yaml=self._input_template.format(module="user_ext_invalid")) ct.Solution(yaml=self._input_template.format(module="user_ext_invalid"))
def test_memory_management(self):
# Make sure objects are being correctly cleaned up and not stuck in
# mixed Python/C++ ownership cycles
import user_ext
gc.collect()
initialRate = user_ext.SquareRate.use_count[0]
initialData = user_ext.SquareRateData.use_count[0]
def run():
gas = ct.Solution("extensible-reactions.yaml", transport_model=None)
assert gas.forward_rate_constants[0] > 0
assert user_ext.SquareRate.use_count[0] == initialRate + 1
assert user_ext.SquareRateData.use_count[0] == initialData + 1
run()
# The number of instances for both classes should go back to its previous value
# after deleting the Solution (may not be zero due to other Solution instances)
# held by other test classes
gc.collect()
assert user_ext.SquareRate.use_count[0] == initialRate
assert user_ext.SquareRateData.use_count[0] == initialData
class InterfaceReactionTests(ReactionTests): class InterfaceReactionTests(ReactionTests):
# test suite for surface reaction expressions # test suite for surface reaction expressions

View File

@ -2,17 +2,32 @@ import cantera as ct
class SquareRateData(ct.ExtensibleRateData): class SquareRateData(ct.ExtensibleRateData):
__slots__ = ("Tsquared",) __slots__ = ("Tsquared",)
use_count = [0] # used in test for memory leak
def __init__(self):
self.use_count[0] += 1
def update(self, gas): def update(self, gas):
self.Tsquared = gas.T**2 self.Tsquared = gas.T**2
return True return True
def __del__(self):
self.use_count[0] -= 1
@ct.extension(name="square-rate", data=SquareRateData) @ct.extension(name="square-rate", data=SquareRateData)
class SquareRate(ct.ExtensibleRate): class SquareRate(ct.ExtensibleRate):
__slots__ = ("A",) __slots__ = ("A",)
use_count = [0] # used in test for memory leak
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.use_count[0] += 1
def set_parameters(self, node, units): def set_parameters(self, node, units):
self.A = node["A"] self.A = node["A"]
def eval(self, data): def eval(self, data):
return self.A * data.Tsquared return self.A * data.Tsquared
def __del__(self):
self.use_count[0] -= 1