Skip to content

Commit

Permalink
Merge pull request #48 from jrenaud90/ver0.8.8
Browse files Browse the repository at this point in the history
Changed memory free functionality
  • Loading branch information
jrenaud90 authored May 1, 2024
2 parents 7195341 + b7b3afe commit da53ff3
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 69 deletions.
10 changes: 9 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

## 2024

#### v0.8.7 (2024-02-13)
#### v0.8.8 (2024-04-30)

New Features:
* Added `utils.free_mem` function to free memory so that future changes to the memory allocation system will call the proper free function that works with the `utils.allocs`.

Changes:
* Changed all instances of `PyMem_Free` to new `free_mem` from the utils.

#### v0.8.7 (2024-04-28)

Updated manifest and rebuilt wheels.

Expand Down
7 changes: 3 additions & 4 deletions CyRK/cy/common.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ from libc.math cimport fmax, fmin, floor
from libc.math cimport INFINITY as INF
from libc.float cimport DBL_EPSILON as EPS
from libc.stdint cimport SIZE_MAX, INT32_MAX
from cpython.mem cimport PyMem_Free

from CyRK.utils.utils cimport allocate_mem, reallocate_mem
from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem
from CyRK.array.interp cimport interp_array_ptr, interp_complex_array_ptr

# # Integration Constants
Expand Down Expand Up @@ -96,10 +95,10 @@ cdef void interpolate(
finally:
# Release memory of any temporary variables
if not (array_slice_ptr is NULL):
PyMem_Free(array_slice_ptr)
free_mem(array_slice_ptr)
array_slice_ptr = NULL
if not (interpolated_array_slice_ptr is NULL):
PyMem_Free(interpolated_array_slice_ptr)
free_mem(interpolated_array_slice_ptr)
interpolated_array_slice_ptr = NULL

cdef size_t find_expected_size(
Expand Down
52 changes: 25 additions & 27 deletions CyRK/cy/cyrk.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@

import cython

from cpython.mem cimport PyMem_Free

import numpy as np
cimport numpy as np

from libc.math cimport sqrt, fabs, nextafter, NAN, floor

from CyRK.utils.utils cimport allocate_mem, reallocate_mem
from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem
from CyRK.rk.rk cimport find_rk_properties
from CyRK.cy.common cimport double_numeric, interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, \
EPS_100, find_expected_size, find_max_num_steps
Expand Down Expand Up @@ -869,14 +867,14 @@ def cyrk_ode(
else:
# Clear the storage arrays used during the step loop
if not (time_domain_array_ptr is NULL):
PyMem_Free(time_domain_array_ptr)
free_mem(time_domain_array_ptr)
time_domain_array_ptr = NULL
if not (y_results_array_ptr is NULL):
PyMem_Free(y_results_array_ptr)
free_mem(y_results_array_ptr)
y_results_array_ptr = NULL
if capture_extra:
if not (extra_array_ptr is NULL):
PyMem_Free(extra_array_ptr)
free_mem(extra_array_ptr)
extra_array_ptr = NULL

# Integration was not successful. Leave the solution pointers as length 1 nan arrays.
Expand Down Expand Up @@ -967,17 +965,17 @@ def cyrk_ode(

# Replace old pointers with new interpolated pointers and release the memory for the old stuff
if not (solution_extra_ptr is NULL):
PyMem_Free(solution_extra_ptr)
free_mem(solution_extra_ptr)
solution_extra_ptr = interpolated_solution_extra_ptr
interpolated_solution_extra_ptr = NULL

# Replace old pointers with new interpolated pointers and release the memory for the old stuff
if not (solution_t_ptr is NULL):
PyMem_Free(solution_t_ptr)
free_mem(solution_t_ptr)
solution_t_ptr = interpolated_solution_t_ptr
interpolated_solution_t_ptr = NULL
if not (solution_y_ptr is NULL):
PyMem_Free(solution_y_ptr)
free_mem(solution_y_ptr)
solution_y_ptr = interpolated_solution_y_ptr
interpolated_solution_y_ptr = NULL

Expand All @@ -1000,14 +998,14 @@ def cyrk_ode(
solution_y_view[extra_start + j, i] = solution_extra_ptr[i * num_extra + j]
# Free solution arrays
if not (solution_t_ptr is NULL):
PyMem_Free(solution_t_ptr)
free_mem(solution_t_ptr)
solution_t_ptr = NULL
if not (solution_y_ptr is NULL):
PyMem_Free(solution_y_ptr)
free_mem(solution_y_ptr)
solution_y_ptr = NULL
if capture_extra:
if not (solution_extra_ptr is NULL):
PyMem_Free(solution_extra_ptr)
free_mem(solution_extra_ptr)
solution_extra_ptr = NULL

# Update integration message
Expand All @@ -1029,55 +1027,55 @@ def cyrk_ode(
finally:
# Free pointers made from user inputs
if not (tol_ptrs is NULL):
PyMem_Free(tol_ptrs)
free_mem(tol_ptrs)
tol_ptrs = NULL
if not (t_eval_ptr is NULL):
PyMem_Free(t_eval_ptr)
free_mem(t_eval_ptr)
t_eval_ptr = NULL

# Free pointers used to track y, dydt, and any extra outputs
if not (y_storage_ptrs is NULL):
PyMem_Free(y_storage_ptrs)
free_mem(y_storage_ptrs)
y_storage_ptrs = NULL
if not (extra_output_init_ptr is NULL):
PyMem_Free(extra_output_init_ptr)
free_mem(extra_output_init_ptr)
extra_output_init_ptr = NULL
if not (extra_output_ptr is NULL):
PyMem_Free(extra_output_ptr)
free_mem(extra_output_ptr)
extra_output_ptr = NULL

# Free RK Temp Storage Array
if not (K_ptr is NULL):
PyMem_Free(K_ptr)
free_mem(K_ptr)
K_ptr = NULL

# Free other pointers that should have been freed in main loop, but in case of an exception they were missed.
if not (solution_t_ptr is NULL):
PyMem_Free(solution_t_ptr)
free_mem(solution_t_ptr)
solution_t_ptr = NULL
if not (solution_y_ptr is NULL):
PyMem_Free(solution_y_ptr)
free_mem(solution_y_ptr)
solution_y_ptr = NULL
if not (solution_extra_ptr is NULL):
PyMem_Free(solution_extra_ptr)
free_mem(solution_extra_ptr)
solution_extra_ptr = NULL
if not (interpolated_solution_t_ptr is NULL):
PyMem_Free(interpolated_solution_t_ptr)
free_mem(interpolated_solution_t_ptr)
interpolated_solution_t_ptr= NULL
if not (interpolated_solution_y_ptr is NULL):
PyMem_Free(interpolated_solution_y_ptr)
free_mem(interpolated_solution_y_ptr)
interpolated_solution_y_ptr = NULL
if not (interpolated_solution_extra_ptr is NULL):
PyMem_Free(interpolated_solution_extra_ptr)
free_mem(interpolated_solution_extra_ptr)
interpolated_solution_extra_ptr = NULL
if not (time_domain_array_ptr is NULL):
PyMem_Free(time_domain_array_ptr)
free_mem(time_domain_array_ptr)
time_domain_array_ptr = NULL
if not (y_results_array_ptr is NULL):
PyMem_Free(y_results_array_ptr)
free_mem(y_results_array_ptr)
y_results_array_ptr = NULL
if not (extra_array_ptr is NULL):
PyMem_Free(extra_array_ptr)
free_mem(extra_array_ptr)
extra_array_ptr = NULL

return solution_t, solution_y, success, message
66 changes: 32 additions & 34 deletions CyRK/cy/cysolver.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@

from libc.math cimport sqrt, fabs, nextafter, fmax, fmin, isnan, NAN, floor

from cpython.mem cimport PyMem_Free

import numpy as np
cimport numpy as np

from CyRK.utils.utils cimport allocate_mem, reallocate_mem
from CyRK.utils.utils cimport allocate_mem, reallocate_mem, free_mem
from CyRK.rk.rk cimport find_rk_properties
from CyRK.cy.common cimport interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, EPS_100, \
find_expected_size, find_max_num_steps
Expand Down Expand Up @@ -894,14 +892,14 @@ cdef class CySolver:
# Solution was successful.
# Free any data stored in solution arrays so that we can repopulate them with the new solution
if not (self.solution_t_ptr is NULL):
PyMem_Free(self.solution_t_ptr)
free_mem(self.solution_t_ptr)
self.solution_t_ptr = NULL
if not (self.solution_y_ptr is NULL):
PyMem_Free(self.solution_y_ptr)
free_mem(self.solution_y_ptr)
self.solution_y_ptr = NULL
if self.capture_extra:
if not (self.solution_extra_ptr is NULL):
PyMem_Free(self.solution_extra_ptr)
free_mem(self.solution_extra_ptr)
self.solution_extra_ptr = NULL

# Load values into solution arrays.
Expand Down Expand Up @@ -931,14 +929,14 @@ cdef class CySolver:
# Integration was not successful. Make solution pointers length 1 nan arrays.
# Clear the storage arrays used during the step loop
if not (self._solve_time_domain_array_ptr is NULL):
PyMem_Free(self._solve_time_domain_array_ptr)
free_mem(self._solve_time_domain_array_ptr)
self._solve_time_domain_array_ptr = NULL
if not (self._solve_y_results_array_ptr is NULL):
PyMem_Free(self._solve_y_results_array_ptr)
free_mem(self._solve_y_results_array_ptr)
self._solve_y_results_array_ptr = NULL
if self.capture_extra:
if not (self._solve_extra_array_ptr is NULL):
PyMem_Free(self._solve_extra_array_ptr)
free_mem(self._solve_extra_array_ptr)
self._solve_extra_array_ptr = NULL

# We still need to build solution arrays so that accessing the solution will not cause access violations.
Expand Down Expand Up @@ -1003,13 +1001,13 @@ cdef class CySolver:

# Release any memory that may still be alive due to exceptions being raised.
if not (self._solve_time_domain_array_ptr is NULL):
PyMem_Free(self._solve_time_domain_array_ptr)
free_mem(self._solve_time_domain_array_ptr)
self._solve_time_domain_array_ptr = NULL
if not (self._solve_y_results_array_ptr is NULL):
PyMem_Free(self._solve_y_results_array_ptr)
free_mem(self._solve_y_results_array_ptr)
self._solve_y_results_array_ptr = NULL
if not (self._solve_extra_array_ptr is NULL):
PyMem_Free(self._solve_extra_array_ptr)
free_mem(self._solve_extra_array_ptr)
self._solve_extra_array_ptr = NULL

cdef void interpolate(self):
Expand Down Expand Up @@ -1097,17 +1095,17 @@ cdef class CySolver:

# Replace old pointers with new interpolated pointers and release the memory for the old stuff
if not (self.solution_extra_ptr is NULL):
PyMem_Free(self.solution_extra_ptr)
free_mem(self.solution_extra_ptr)
self.solution_extra_ptr = self._interpolate_solution_extra_ptr
self._interpolate_solution_extra_ptr = NULL

# Replace old pointers with new interpolated pointers and release the memory for the old stuff
if not (self.solution_t_ptr is NULL):
PyMem_Free(self.solution_t_ptr)
free_mem(self.solution_t_ptr)
self.solution_t_ptr = self._interpolate_solution_t_ptr
self._interpolate_solution_t_ptr = NULL
if not (self.solution_y_ptr is NULL):
PyMem_Free(self.solution_y_ptr)
free_mem(self.solution_y_ptr)
self.solution_y_ptr = self._interpolate_solution_y_ptr
self._interpolate_solution_y_ptr = NULL

Expand All @@ -1116,13 +1114,13 @@ cdef class CySolver:

# Free any memory that may still be alive if exceptions were raised.
if not (self._interpolate_solution_t_ptr is NULL):
PyMem_Free(self._interpolate_solution_t_ptr)
free_mem(self._interpolate_solution_t_ptr)
self._interpolate_solution_t_ptr = NULL
if not (self._interpolate_solution_y_ptr is NULL):
PyMem_Free(self._interpolate_solution_y_ptr)
free_mem(self._interpolate_solution_y_ptr)
self._interpolate_solution_y_ptr = NULL
if not (self._interpolate_solution_extra_ptr is NULL):
PyMem_Free(self._interpolate_solution_extra_ptr)
free_mem(self._interpolate_solution_extra_ptr)
self._interpolate_solution_extra_ptr = NULL

cpdef void change_t_span(
Expand Down Expand Up @@ -1691,60 +1689,60 @@ cdef class CySolver:
def __dealloc__(self):
# Free pointers made from user inputs
if not (self.y0_ptr is NULL):
PyMem_Free(self.y0_ptr)
free_mem(self.y0_ptr)
self.y0_ptr = NULL
if not (self.tol_ptrs is NULL):
PyMem_Free(self.tol_ptrs)
free_mem(self.tol_ptrs)
self.tol_ptrs = NULL
if not (self.args_ptr is NULL):
PyMem_Free(self.args_ptr)
free_mem(self.args_ptr)
self.args_ptr = NULL
if not (self.t_eval_ptr is NULL):
PyMem_Free(self.t_eval_ptr)
free_mem(self.t_eval_ptr)
self.t_eval_ptr = NULL

# Free pointers used to track y, dydt, and any extra outputs
if not (self.temporary_y_ptrs is NULL):
PyMem_Free(self.temporary_y_ptrs)
free_mem(self.temporary_y_ptrs)
self.temporary_y_ptrs = NULL
if not (self.extra_output_ptrs is NULL):
PyMem_Free(self.extra_output_ptrs)
free_mem(self.extra_output_ptrs)
self.extra_output_ptrs = NULL

# Free final solution pointers
if not (self.solution_t_ptr is NULL):
PyMem_Free(self.solution_t_ptr)
free_mem(self.solution_t_ptr)
self.solution_t_ptr = NULL
if not (self.solution_y_ptr is NULL):
PyMem_Free(self.solution_y_ptr)
free_mem(self.solution_y_ptr)
self.solution_y_ptr = NULL
if not (self.solution_extra_ptr is NULL):
PyMem_Free(self.solution_extra_ptr)
free_mem(self.solution_extra_ptr)
self.solution_extra_ptr = NULL

# Free pointers used during the solve method
if not (self._solve_time_domain_array_ptr is NULL):
PyMem_Free(self._solve_time_domain_array_ptr)
free_mem(self._solve_time_domain_array_ptr)
self._solve_time_domain_array_ptr = NULL
if not (self._solve_y_results_array_ptr is NULL):
PyMem_Free(self._solve_y_results_array_ptr)
free_mem(self._solve_y_results_array_ptr)
self._solve_y_results_array_ptr = NULL
if not (self._solve_extra_array_ptr is NULL):
PyMem_Free(self._solve_extra_array_ptr)
free_mem(self._solve_extra_array_ptr)
self._solve_extra_array_ptr = NULL

# Free pointers used during interpolation
if not (self._interpolate_solution_t_ptr is NULL):
PyMem_Free(self._interpolate_solution_t_ptr)
free_mem(self._interpolate_solution_t_ptr)
self._interpolate_solution_t_ptr = NULL
if not (self._interpolate_solution_y_ptr is NULL):
PyMem_Free(self._interpolate_solution_y_ptr)
free_mem(self._interpolate_solution_y_ptr)
self._interpolate_solution_y_ptr = NULL
if not (self._interpolate_solution_extra_ptr is NULL):
PyMem_Free(self._interpolate_solution_extra_ptr)
free_mem(self._interpolate_solution_extra_ptr)
self._interpolate_solution_extra_ptr = NULL

# Free RK Temp Storage Array
if not (self.K_ptr is NULL):
PyMem_Free(self.K_ptr)
free_mem(self.K_ptr)
self.K_ptr = NULL
2 changes: 2 additions & 0 deletions CyRK/utils/utils.pxd
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cdef void* allocate_mem(size_t size, char* var_name)

cdef void* reallocate_mem(void* old_pointer, size_t new_size, char* var_name)

cdef void free_mem(void* mem_pointer)
5 changes: 4 additions & 1 deletion CyRK/utils/utils.pyx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# distutils: language = c
# cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False
from cpython.mem cimport PyMem_Malloc, PyMem_Realloc
from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free


cdef inline void* allocate_mem(size_t size, char* var_name):
Expand All @@ -15,3 +15,6 @@ cdef inline void* reallocate_mem(void* old_pointer, size_t new_size, char* var_n
if not new_memory:
raise MemoryError(f'Failed to *re*allocate memory for {var_name}\n\tRequested size = {new_size}.')
return new_memory

cdef inline void free_mem(void* mem_pointer):
PyMem_Free(mem_pointer)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

---

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


**Runge-Kutta ODE Integrator Implemented in Cython and Numba**
Expand Down
Loading

0 comments on commit da53ff3

Please sign in to comment.