Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bad array returns #81

Merged
merged 8 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions .github/workflows/push_tests_ubun.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,33 @@ jobs:
- name: Run pytest
run: pytest -n auto -v Tests/

test-39-with-coverage:
name: Test Python 3.9 and Upload Coverage Report
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: 3.9
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pytest pytest-cov cython pytest-xdist
- name: Install package
run: |
python -m pip install . -v
# test-39-with-coverage:
# name: Test Python 3.9 and Upload Coverage Report
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Set up Python 3.9
# uses: actions/setup-python@v5
# with:
# python-version: 3.9
# - name: Install Dependencies
# run: |
# python -m pip install --upgrade pip
# python -m pip install pytest pytest-cov cython pytest-xdist
# - name: Install package
# run: |
# python -m pip install . -v

- name: Run pytest
run: pytest -n auto --capture=sys -v --cov=CyRK Tests/
env:
# Disable numba so that njited functions can have their coverage checked.
NUMBA_DISABLE_JIT: 1
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
env_vars: OS,PYTHON
fail_ci_if_error: false
flags: unittests
verbose: true
name: coverage
# - name: Run pytest
# run: pytest -n auto --capture=sys -v --cov=CyRK Tests/
# env:
# # Disable numba so that njited functions can have their coverage checked.
# NUMBA_DISABLE_JIT: 1
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v3
# with:
# env_vars: OS,PYTHON
# fail_ci_if_error: false
# flags: unittests
# verbose: true
# name: coverage
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## 2024

#### v0.12.1 (2024-12-02)

Fixes:
* Added fix so that arrays returned by `WrapCySolverResult` class are not destroyed when class is. Instead they are managed by python's garbage collector once they are held by a python variable. This addresses Github issues [#80](https://github.com/jrenaud90/CyRK/issues/80) and [#78](https://github.com/jrenaud90/CyRK/issues/78)

Tests:
* Added test to check that arrays stay alive after underlying `WrapCySolverResult` class is destroyed.

#### v0.12.0 (2024-12-02)

New & Changes:
Expand Down
8 changes: 4 additions & 4 deletions CyRK/cy/cysolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ CySolverBase::CySolverBase(
const double* t_eval,
const size_t len_t_eval,
PreEvalFunc pre_eval_func) :
t_start(t_start),
t_end(t_end),
diffeq_ptr(diffeq_ptr),
size_of_args(size_of_args),
len_t_eval(len_t_eval),
num_extra(num_extra),
use_dense_output(use_dense_output),
pre_eval_func(pre_eval_func),
status(0),
num_y(num_y),
storage_sptr(storage_sptr)
num_extra(num_extra),
storage_sptr(storage_sptr),
t_start(t_start),
t_end(t_end)
{
// Parse inputs
this->capture_extra = num_extra > 0;
Expand Down
12 changes: 6 additions & 6 deletions CyRK/cy/cysolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class CySolverBase {


public:
// Differential equation information
DiffeqFuncType diffeq_ptr = nullptr;

// Integration step information
size_t max_num_steps = 0;

Expand All @@ -111,9 +114,6 @@ class CySolverBase {
std::vector<char> args_char_vec = std::vector<char>();
char* args_ptr = nullptr;

// Differential equation information
DiffeqFuncType diffeq_ptr = nullptr;

// t_eval information
std::vector<double> t_eval_vec = std::vector<double>();
double* t_eval_ptr = t_eval_vec.data();
Expand All @@ -122,9 +122,6 @@ class CySolverBase {
bool skip_t_eval = false;
bool use_t_eval = false;

// Function to send to diffeq which is called before dy is calculated
PreEvalFunc pre_eval_func = nullptr;

// Keep bools together to reduce size
bool direction_flag = false;
bool reset_called = false;
Expand All @@ -134,6 +131,9 @@ class CySolverBase {

// Dense (Interpolation) Attributes
bool use_dense_output = false;

// Function to send to diffeq which is called before dy is calculated
PreEvalFunc pre_eval_func = nullptr;

// PySolver Attributes
bool use_pysolver = false;
Expand Down
4 changes: 2 additions & 2 deletions CyRK/cy/cysolver_api.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,11 @@ cdef class WrapCySolverResult:

@property
def t(self):
return np.asarray(self.time_view, dtype=np.float64, order='C')
return np.copy(np.asarray(self.time_view, dtype=np.float64, order='C'))

@property
def y(self):
return np.asarray(self.y_view, dtype=np.float64, order='C').reshape((self.size, self.num_dy)).T
return np.copy(np.asarray(self.y_view, dtype=np.float64, order='C')).reshape((self.size, self.num_dy)).T

@property
def size(self):
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div style="text-align: center;">
<a href="https://doi.org/10.5281/zenodo.7093266"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.7093266.svg" alt="DOI"></a>
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/Python-3.8|3.9|3.10|3.11|3.12-blue" alt="Python Version 3.8-3.12" /></a>
<a href="https://codecov.io/gh/jrenaud90/CyRK" ><img src="https://codecov.io/gh/jrenaud90/CyRK/branch/main/graph/badge.svg?token=MK2PqcNGET" alt="Code Coverage"/></a>
<!-- <a href="https://codecov.io/gh/jrenaud90/CyRK" ><img src="https://codecov.io/gh/jrenaud90/CyRK/branch/main/graph/badge.svg?token=MK2PqcNGET" alt="Code Coverage"/></a> -->
<br />
<a href="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_win.yml"><img src="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_win.yml/badge.svg?branch=main" alt="Windows Tests" /></a>
<a href="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_mac.yml"><img src="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_mac.yml/badge.svg?branch=main" alt="MacOS Tests" /></a>
Expand All @@ -11,7 +11,7 @@

---

<a href="https://github.com/jrenaud90/CyRK/releases"><img src="https://img.shields.io/badge/CyRK-0.12.0 Alpha-orange" alt="CyRK Version 0.12.0 Alpha" /></a>
<a href="https://github.com/jrenaud90/CyRK/releases"><img src="https://img.shields.io/badge/CyRK-0.12.1 Alpha-orange" alt="CyRK Version 0.12.1 Alpha" /></a>


**Runge-Kutta ODE Integrator Implemented in Cython and Numba**
Expand Down
45 changes: 45 additions & 0 deletions Tests/D_PySolver_Tests/test_d_pysolve_array_lifetime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import numpy as np
from CyRK import pysolve_ivp
import gc


def diffeq(dy, t, y):
dy[0] = (1. - 0.01 * y[1]) * y[0]
dy[1] = (0.02 * y[0] - 1.) * y[1]

initial_conds = np.asarray((20., 20.), dtype=np.float64, order='C')
time_span = (0., 10.)
time_span_large = (0., 1000.)
rtol = 1.0e-4
atol = 1.0e-7

def run_diffeq_array_return():
result = pysolve_ivp(diffeq, time_span, initial_conds, method="RK45", rtol=rtol, atol=atol, pass_dy_as_arg=True)

t = result.t
y = result.y
del result
gc.collect()
return t, y

def run_diffeq_result_return():
result = pysolve_ivp(diffeq, time_span, initial_conds, method="RK45", rtol=rtol, atol=atol, pass_dy_as_arg=True)
return result

def test_pysolve_array_lifetimes():
""" Tests that the underlying arrays returned by the WrapCySolverResult class can outlive the class instance. """

# Run in a loop because sometimes memory corruptions can take a while to appear
for i in range(50):
# Get result from the result instance class
result = run_diffeq_result_return()

# Get arrays from the array return
t, y = run_diffeq_array_return()

# Check that they contain the same data
assert result.y.size == y.size
assert result.t.size == t.size

assert np.allclose(result.y, y)
assert np.allclose(result.t, t)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name='CyRK'
version = '0.12.0'
version = '0.12.1'
description='Runge-Kutta ODE Integrator Implemented in Cython and Numba.'
authors= [
{name = 'Joe P. Renaud', email = '[email protected]'}
Expand Down
Loading