forked from perwin/pyimfit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
notes_for_python-wrapper_code.txt
192 lines (138 loc) · 7.66 KB
/
notes_for_python-wrapper_code.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
NOTES FOR CYTHON WRAPPER FOR IMFIT:
[] Model description and parameter input
Write Python code to parse imfit config file and return object with
info
-- also write Python functions to make it easy to construct
similar object
Imfit vs Makeimage config files
-- flag in object specifying absence of fitting-related info?
(parameter limits, data image, etc.)
Two or three levels of "model description"
1. Basic model as for makeimage: functions, parameter values, PSF image(s)
2. Data images, error & mask images, parameter limits
3. Fitting statistic to be used
[] Better function handling
Andre's FunctionDescription class allows the user to specify the name and
parameter values (and limits) for a function. E.g.
exponential = function_description('Exponential')
exponential.PA.setValue(93.0217, [0, 180])
exponential.ell.setValue(0.37666, [0, 1])
exponential.I_0.setValue(1, [0, 10])
exponential.h.setValue(25, [0, 100])
BUT there is no checking of parameter names: "exponential.PA.setValue"
automatically creates an attribute named "PA"
but with NO checks to see if
these are valid p
[] std::tuple issues
Since Cython doesn't understand C++ std::tuple, but *does* understand std::pair,
we may need to convert some of our C++ code that returns tuples so that it returns
a pair [assuming it returns 2 values!].
However, this will only be an issue if we need to call one of the C++ functions
or methods from Python. So for the time being, we won't worry about it...
[] Functions and object to expose in Python
struct mp_par
struct mp_result ?
class ModelObject
class Convolver
solver functions:
DispatchToSolver ?
DiffEvolnFit
LevMarFit
NMSimplexFit
NLOptFit
class SolverResults [needed for input/output to solver functions]
cdef extern from 'imfit/add_functions.h':
int AddFunctions(ModelObject *theModel, vector[string] &functionNameList,
vector[int] &functionSetIndices, bool subamplingFlag, bool verbose)
int GetFunctionParameters(string &functionName, vector[string] ¶meterNameList)
void GetFunctionNames(vector[string] &functionNameList)
cdef extern from 'imfit/definitions.h':
int WEIGHTS_ARE_SIGMAS = 100 # "weight image" pixel value = sigma
int WEIGHTS_ARE_VARIANCES = 110 # "weight image" pixel value = variance (sigma^2)
int WEIGHTS_ARE_WEIGHTS = 120 # "weight image" pixel value = weight
int MASK_ZERO_IS_GOOD = 10 # "standard" input mask format (good pixels = 0)
int MASK_ZERO_IS_BAD = 20 # alternate input mask format (good pixels = 1)
[maybe -- we could replace these with Python code, but since we already have the
C++ code...]
cdef extern from 'imfit/statistics.h':
double AIC_corrected(double logLikelihood, int nParams, long nData, int chiSquareUsed)
double BIC(double logLikelihood, int nParams, long nData, int chiSquareUsed)
[] Image array issues:
[] Byte-order (endian-ness) issues:
astropy.fits reads in FITS images as big-endian, 4-byte (single-precision floating point)
array.dtype.byteorder [possible values: '<' for little-endian, '>' for big-endian,
'=' for same as current OS/computer]
our code ultimately wants the data as little-endian, double-precision
# Python code snippet to check for and fix byte order
sys_byteorder = ('>', '<')[sys.byteorder == 'little']
def FixByteOrder( array ):
if array.dtype.byteorder not in ('=', sys_byteorder):
array = array.byteswap().newbyteorder(sys_byteorder)
return array
[] floating-point size
astropy.fits will often read a FITS image as 32-bit float (or possibly something
simpler or stranger)
Our code wants the data as double-precision
# Python code snippet to convert to double-precision (and C ordering)
array_fixed = array.astype(dtype=np.float64, order='C')
[] 1D vs 2D layout
astropy.fits produces 2D numpy arrays, in C ordering
Our code wants *1D* arrays (with implicit C ordering)
# Python code snippet for converting to and from 1D format
image_x, image_y = image.shape[1], image.shape[0]
(OR: image_y, image_x = image.shape)
image_1d = image.flatten()
...
...
...
image_output = image_1d.reshape((image_y, image_x))
[] Converting Numpy (1D) array to and from C++ double *
Assuming we have a C++ function that wants a double *, e.g.
void SomeCppFunction( double * input, ...)
# Cython code snippet using typed memoryview
cdef double[::1] image_data = image_1d
SomeCppFunction(&image_data[0], ...)
[] Future ideas
[] Things we might want to do
1. Load an image
2. Specify image parameters
3. Both at once
==> DataObject
-- image data
-- error image
-- mask image
-- gain, readnoise, etc.
1. Specify a model
2. Specify parameter values for model
==> DataObject
-- can be used to output model image (makeimage style)
-- can be used for fitting
1. Combined DataObject and ModelObject
1. Run GetFitStatistic multiple times, each time with a different
parameter vector
import pyimfit
testDataDir = "/Users/erwin/coding/pyimfit_working/pyimfit/data/"
imageFile = testDataDir + "ic3478rss_256.fits"
configFile = testDataDir + "config_exponential_ic3478_256.dat"
model_desc = pyimfit.ModelDescription.load(configFile)
imfit_fitter = pyimfit.Imfit(model_desc)
image_ic3478 = pyimfit.FixImage(fits.getdata(imageFile))
model_desc = pyimfit.ModelDescription.load(configFile)
-- creates ModelDescription instance
imfit_fitter = pyimfit.Imfit(model_desc)
-- creates Imfit instance with model_desc as input
fitting.Imfit.__init__(self, model_desc)
[x] Imfit: self._verboseLevel = -1
imfit_fitter.fit(image_ic3478, gain=4.725, read_noise=4.3, original_sky=130.14)
fitting.Imfit.fit()
self._setupModel()
self._modelObject = ModelObjectWrapper(self._modelDescr, self._debugLevel,
self._verboseLevel, self._subsampling)
self._modelObject.loadData(image, error, mask, **kwargs)
self._modelObject.fit(verbose=self._verboseLevel, mode=mode)
[] Change fitting.Imfit's "self._modelObject" to "self._modelObjectWrapper" ?
-- makes it clearer that this is instance of ModelObjectWrapper, not
of [C++] ModelObject
pyimfit_lib.pyx:
ModelObjectWrapper
self._model