Skip to content

Commit

Permalink
Remove all remaining wrappers.
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamJamieson committed Oct 11, 2023
1 parent f30e939 commit 0178b75
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 146 deletions.
6 changes: 0 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@
include_dirs=[np.get_include()],
language='c++'
),
Extension(
'stcal.ramp_fitting.ols_cas22._wrappers',
['src/stcal/ramp_fitting/ols_cas22/_wrappers.pyx'],
include_dirs=[np.get_include()],
language='c++'
),
]

setup(ext_modules=cythonize(extensions))
2 changes: 1 addition & 1 deletion src/stcal/ramp_fitting/ols_cas22/_fixed.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ cdef class FixedValues:
cdef float[:, :] var_slope_vals(FixedValues self)


cdef FixedValues fixed_values_from_metadata(ReadPatternMetadata data, Thresh threshold, bool use_jump)
cpdef FixedValues fixed_values_from_metadata(ReadPatternMetadata data, Thresh threshold, bool use_jump)
66 changes: 62 additions & 4 deletions src/stcal/ramp_fitting/ols_cas22/_fixed.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ FixedValues : class
Functions
---------
fixed_values_from_metadata : function
Fast constructor for FixedValues from the read pattern metadata
fixed_values_from_metadata : function
Fast constructor for FixedValues from the read pattern metadata
- cpdef gives a python wrapper, but the python version of this method
is considered private, only to be used for testing
"""
import numpy as np
cimport numpy as np
Expand Down Expand Up @@ -175,8 +177,64 @@ cdef class FixedValues:

return var_slope_vals


cdef inline FixedValues fixed_values_from_metadata(ReadPatternMetadata data, Thresh threshold, bool use_jump):
def _to_dict(FixedValues self):
"""
This is a private method to convert the FixedValues object to a dictionary,
so that attributes can be directly accessed in python. Note that this
is needed because class attributes cannot be accessed on cython classes
directly in python. Instead they need to be accessed or set using a
python compatible method. This method is a pure puthon method bound
to to the cython class and should not be used by any cython code, and
only exists for testing purposes.
"""
cdef np.ndarray[float, ndim=2] t_bar_diffs
cdef np.ndarray[float, ndim=2] t_bar_diff_sqrs
cdef np.ndarray[float, ndim=2] read_recip_coeffs
cdef np.ndarray[float, ndim=2] var_slope_coeffs

if self.use_jump:
t_bar_diffs = np.array(self.t_bar_diffs, dtype=np.float32)
t_bar_diff_sqrs = np.array(self.t_bar_diff_sqrs, dtype=np.float32)
read_recip_coeffs = np.array(self.read_recip_coeffs, dtype=np.float32)
var_slope_coeffs = np.array(self.var_slope_coeffs, dtype=np.float32)
else:
try:
self.t_bar_diffs
except AttributeError:
t_bar_diffs = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("t_bar_diffs should not exist")

try:
self.t_bar_diff_sqrs
except AttributeError:
t_bar_diff_sqrs = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("t_bar_diff_sqrs should not exist")

try:
self.read_recip_coeffs
except AttributeError:
read_recip_coeffs = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("read_recip_coeffs should not exist")

try:
self.var_slope_coeffs
except AttributeError:
var_slope_coeffs = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("var_slope_coeffs should not exist")

return dict(data=self.data,
threshold=self.threshold,
t_bar_diffs=t_bar_diffs,
t_bar_diff_sqrs=t_bar_diff_sqrs,
read_recip_coeffs=read_recip_coeffs,
var_slope_coeffs=var_slope_coeffs)


cpdef inline FixedValues fixed_values_from_metadata(ReadPatternMetadata data, Thresh threshold, bool use_jump):
"""
Fast constructor for FixedValues class
Use this instead of an __init__ because it does not incure the overhead
Expand Down
2 changes: 1 addition & 1 deletion src/stcal/ramp_fitting/ols_cas22/_pixel.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ cdef class Pixel:
cdef RampFits fit_ramps(Pixel self, stack[RampIndex] ramps)


cdef Pixel make_pixel(FixedValues fixed, float read_noise, float [:] resultants)
cpdef Pixel make_pixel(FixedValues fixed, float read_noise, float [:] resultants)
48 changes: 45 additions & 3 deletions src/stcal/ramp_fitting/ols_cas22/_pixel.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ Pixel : class
Functions
---------
make_pixel : function
Fast constructor for a Pixel class from input data.
make_pixel : function
Fast constructor for a Pixel class from input data.
- cpdef gives a python wrapper, but the python version of this method
is considered private, only to be used for testing
"""
from libc.math cimport sqrt, fabs
from libcpp.vector cimport vector
Expand Down Expand Up @@ -473,10 +475,50 @@ cdef class Pixel:

return ramp_fits

def _to_dict(Pixel self):
"""
This is a private method to convert the Pixel object to a dictionary, so
that attributes can be directly accessed in python. Note that this is
needed because class attributes cannot be accessed on cython classes
directly in python. Instead they need to be accessed or set using a
python compatible method. This method is a pure puthon method bound
to to the cython class and should not be used by any cython code, and
only exists for testing purposes.
"""

cdef np.ndarray[float, ndim=1] resultants_ = np.array(self.resultants, dtype=np.float32)

cdef np.ndarray[float, ndim=2] local_slopes
cdef np.ndarray[float, ndim=2] var_read_noise

if self.fixed.use_jump:
local_slopes = np.array(self.local_slopes, dtype=np.float32)
var_read_noise = np.array(self.var_read_noise, dtype=np.float32)
else:
try:
self.local_slopes
except AttributeError:
local_slopes = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("local_slopes should not exist")

try:
self.var_read_noise
except AttributeError:
var_read_noise = np.array([[np.nan],[np.nan]], dtype=np.float32)
else:
raise AttributeError("var_read_noise should not exist")

return dict(fixed=self.fixed._to_dict(),
resultants=resultants_,
read_noise=self.read_noise,
local_slopes=local_slopes,
var_read_noise=var_read_noise)


@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline Pixel make_pixel(FixedValues fixed, float read_noise, float [:] resultants):
cpdef inline Pixel make_pixel(FixedValues fixed, float read_noise, float [:] resultants):
"""
Fast constructor for the Pixel C class.
This creates a Pixel object for a single pixel from the input data.
Expand Down
121 changes: 0 additions & 121 deletions src/stcal/ramp_fitting/ols_cas22/_wrappers.pyx

This file was deleted.

51 changes: 41 additions & 10 deletions tests/test_jump_cas22.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from numpy.testing import assert_allclose

from stcal.ramp_fitting.ols_cas22._core import metadata_from_read_pattern, threshold
from stcal.ramp_fitting.ols_cas22._wrappers import fixed_values_from_metadata, make_pixel
from stcal.ramp_fitting.ols_cas22._fixed import fixed_values_from_metadata
from stcal.ramp_fitting.ols_cas22._pixel import make_pixel

from stcal.ramp_fitting.ols_cas22 import fit_ramps, Parameter, Variance, Diff, RampJumpDQ

Expand Down Expand Up @@ -126,7 +127,7 @@ def test_threshold():
intercept - constant * log10(slope) = threshold
"""

# Create the python analog of the threshold struct
# Create the python analog of the Threshold struct
# Note that structs get mapped to/from python as dictionary objects with
# the keys being the struct members.
thresh = {
Expand Down Expand Up @@ -174,17 +175,33 @@ def test_fixed_values_from_metadata(ramp_data, use_jump):
"""Test computing the fixed data for all pixels"""
_, t_bar, tau, n_reads = ramp_data

intercept = np.float32(5.5)
constant = np.float32(1/3)
# Create the python analog of the ReadPatternMetadata struct
# Note that structs get mapped to/from python as dictionary objects with
# the keys being the struct members.
data = {
"t_bar": t_bar,
"tau": tau,
"n_reads": n_reads,
}

# Create the python analog of the Threshold struct
# Note that structs get mapped to/from python as dictionary objects with
# the keys being the struct members.
thresh = {
'intercept': np.float32(5.5),
'constant': np.float32(1/3)
}

fixed = fixed_values_from_metadata(t_bar, tau, n_reads, intercept, constant, use_jump)
# Note this is converted to a dictionary so we can directly interrogate the
# variables in question
fixed = fixed_values_from_metadata(data, thresh, use_jump)._to_dict()

# Basic sanity checks that data passed in survives
assert (fixed['data']['t_bar'] == t_bar).all()
assert (fixed['data']['tau'] == tau).all()
assert (fixed['data']['n_reads'] == n_reads).all()
assert fixed["intercept"] == intercept
assert fixed["constant"] == constant
assert fixed['threshold']["intercept"] == thresh['intercept']
assert fixed['threshold']["constant"] == thresh['constant']

# Check the computed data
# These are computed via vectorized operations in the main code, here we
Expand Down Expand Up @@ -298,15 +315,29 @@ def test_make_pixel(pixel_data, use_jump):
"""Test computing the initial pixel data"""
resultants, t_bar, tau, n_reads = pixel_data

intercept = np.float32(5.5)
constant = np.float32(1/3)
# Create a fixed object to pass into the constructor
# This requires setting up some structs as dictionaries
data = {
"t_bar": t_bar,
"tau": tau,
"n_reads": n_reads,
}
thresh = {
'intercept': np.float32(5.5),
'constant': np.float32(1/3)
}
fixed = fixed_values_from_metadata(data, thresh, use_jump)

pixel = make_pixel(resultants, t_bar, tau, n_reads, READ_NOISE, intercept, constant, use_jump)
# Note this is converted to a dictionary so we can directly interrogate the
# variables in question
pixel = make_pixel(fixed, READ_NOISE, resultants)._to_dict()

# Basic sanity checks that data passed in survives
assert (pixel['resultants'] == resultants).all()
assert READ_NOISE == pixel['read_noise']

# the "fixed" data is not checked as this is already done above

# Check the computed data
# These are computed via vectorized operations in the main code, here we
# check using item-by-item operations
Expand Down

0 comments on commit 0178b75

Please sign in to comment.