-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fixed Gaussian2D model #2038
Fixed Gaussian2D model #2038
Changes from all commits
fe8a9be
f7f8779
2850e9a
e6f5bda
c67e8b9
ad4565f
27df53d
7a88c9f
c5011c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,11 +34,11 @@ class Gaussian1D(Parametric1DModel): | |
Parameters | ||
---------- | ||
amplitude : float | ||
Amplitude of the gaussian | ||
Amplitude of the Gaussian. | ||
mean : float | ||
Mean of the gaussian | ||
Mean of the Gaussian. | ||
stddev : float | ||
Standard deviation of the gaussian | ||
Standard deviation of the Gaussian. | ||
|
||
Notes | ||
----- | ||
|
@@ -102,17 +102,18 @@ def __init__(self, amplitude, mean, stddev, **constraints): | |
super(Gaussian1D, self).__init__(param_dim=param_dim, | ||
amplitude=amplitude, mean=mean, | ||
stddev=stddev, **constraints) | ||
|
||
@staticmethod | ||
def eval(x, amplitude, mean, stddev): | ||
""" | ||
Model function Gauss1D | ||
Gaussian1D model function. | ||
""" | ||
return amplitude * np.exp(- 0.5 * (x - mean) ** 2 / stddev ** 2) | ||
|
||
@staticmethod | ||
def fit_deriv(x, amplitude, mean, stddev): | ||
""" | ||
Model function derivatives Gauss1D | ||
Gaussian1D model function derivatives. | ||
""" | ||
|
||
d_amplitude = np.exp(-0.5 / stddev ** 2 * (x - mean) ** 2) | ||
|
@@ -128,22 +129,24 @@ class Gaussian2D(Parametric2DModel): | |
Parameters | ||
---------- | ||
amplitude : float | ||
Amplitude of the gaussian | ||
Amplitude of the Gaussian. | ||
x_mean : float | ||
Mean of the gaussian in x | ||
Mean of the Gaussian in x. | ||
y_mean : float | ||
Mean of the gaussian in y | ||
Mean of the Gaussian in y. | ||
x_stddev : float | ||
Standard deviation of the gaussian in x | ||
Either x_fwhm or x_stddev must be specified | ||
Standard deviation of the Gaussian in x. | ||
x_stddev and y_stddev must be specified unless a covariance | ||
matrix (cov_matrix) is input. | ||
y_stddev : float | ||
Standard deviation of the gaussian in y | ||
Either y_fwhm or y_stddev must be specified | ||
theta : float | ||
Rotation angle in radians. Note: increases clockwise. | ||
cov_matrix : ndarray | ||
A 2x2 covariance matrix. If specified, overrides stddev, fwhm, and | ||
theta specification. | ||
Standard deviation of the Gaussian in y. | ||
x_stddev and y_stddev must be specified unless a covariance | ||
matrix (cov_matrix) is input. | ||
theta : float, optional | ||
Rotation angle in radians. The rotation angle increases clockwise. | ||
cov_matrix : ndarray, optional | ||
A 2x2 covariance matrix. If specified, overrides the x_stddev, | ||
y_stddev, and theta specification. | ||
|
||
Notes | ||
----- | ||
|
@@ -157,14 +160,14 @@ class Gaussian2D(Parametric2DModel): | |
Using the following definitions: | ||
|
||
.. math:: | ||
a = \\left(- \\frac{\\sin^{2}{\\left (\\theta \\right )}}{2 \\sigma_{y}^{2}} - | ||
\\frac{\\cos^{2}{\\left (\\theta \\right )}}{2 \\sigma_{x}^{2}}\\right) | ||
a = \\left(\\frac{\\cos^{2}{\\left (\\theta \\right )}}{2 \\sigma_{x}^{2}} + | ||
\\frac{\\sin^{2}{\\left (\\theta \\right )}}{2 \\sigma_{y}^{2}}\\right) | ||
|
||
b = \\left(\\frac{\\sin{\\left (2 \\theta \\right )}}{2 \\sigma_{y}^{2}} - | ||
\\frac{\\sin{\\left (2 \\theta \\right )}}{2 \\sigma_{x}^{2}}\\right) | ||
b = \\left(\\frac{-\\sin{\\left (2 \\theta \\right )}}{2 \\sigma_{x}^{2}} + | ||
\\frac{\\sin{\\left (2 \\theta \\right )}}{2 \\sigma_{y}^{2}}\\right) | ||
|
||
c = \\left(\\frac{\\cos^{2}{\\left (\\theta \\right )}}{2 \\sigma_{y}^{2}} + | ||
\\frac{\\sin^{2}{\\left (\\theta \\right )}}{2 \\sigma_{x}^{2}}\\right) | ||
c = \\left(\\frac{\\sin^{2}{\\left (\\theta \\right )}}{2 \\sigma_{x}^{2}} + | ||
\\frac{\\cos^{2}{\\left (\\theta \\right )}}{2 \\sigma_{y}^{2}}\\right) | ||
|
||
|
||
See Also | ||
|
@@ -183,11 +186,11 @@ def __init__(self, amplitude, x_mean, y_mean, x_stddev=None, y_stddev=None, | |
theta=0.0, cov_matrix=None, **constraints): | ||
if y_stddev is None and cov_matrix is None: | ||
raise InputParameterError( | ||
"Either y_stddev must be specified, or a " | ||
"Either x/y_stddev must be specified, or a " | ||
"covariance matrix.") | ||
elif x_stddev is None and cov_matrix is None: | ||
raise InputParameterError( | ||
"Either x_stddev must be specified, or a " | ||
"Either x/y_stddev must be specified, or a " | ||
"covariance matrix.") | ||
elif cov_matrix is not None and (x_stddev is not None or | ||
y_stddev is not None): | ||
|
@@ -211,54 +214,65 @@ def __init__(self, amplitude, x_mean, y_mean, x_stddev=None, y_stddev=None, | |
def eval(x, y, amplitude, x_mean, y_mean, x_stddev, y_stddev, theta): | ||
"""Two dimensional Gaussian function""" | ||
|
||
a = 0.5 * ((np.cos(theta) / x_stddev) ** 2 + | ||
(np.sin(theta) / y_stddev) ** 2) | ||
b = 0.5 * (np.cos(theta) * np.sin(theta) * | ||
(1. / x_stddev ** 2 - 1. / y_stddev ** 2)) | ||
c = 0.5 * ((np.sin(theta) / x_stddev) ** 2 + | ||
(np.cos(theta) / y_stddev) ** 2) | ||
|
||
return amplitude * np.exp(-(a * (x - x_mean) ** 2 + | ||
b * (x - x_mean) * (y - y_mean) + | ||
c * (y - y_mean) ** 2)) | ||
cost2 = np.cos(theta) ** 2 | ||
sint2 = np.sin(theta) ** 2 | ||
sin2t = np.sin(2. * theta) | ||
xstd2 = x_stddev ** 2 | ||
ystd2 = y_stddev ** 2 | ||
xdiff = x - x_mean | ||
ydiff = y - y_mean | ||
a = 0.5 * ((cost2 / xstd2) + (sint2 / ystd2)) | ||
b = 0.5 * (-(sin2t / xstd2) + (sin2t / ystd2)) | ||
c = 0.5 * ((sint2 / xstd2) + (cost2 / ystd2)) | ||
return amplitude * np.exp(-((a * xdiff ** 2) + (b * xdiff * ydiff) + | ||
(c * ydiff ** 2))) | ||
|
||
@staticmethod | ||
def fit_deriv(x, y, amplitude, x_mean, y_mean, x_stddev, y_stddev, theta): | ||
"""Two dimensional Gaussian function derivative with respect to parameters""" | ||
|
||
# Helper quantities | ||
a = 0.5 * ((np.cos(theta) / x_stddev) ** 2 + | ||
(np.sin(theta) / y_stddev) ** 2) | ||
b = 0.5 * (np.cos(theta) * np.sin(theta) * | ||
(1. / x_stddev ** 2 - 1. / y_stddev ** 2)) | ||
c = 0.5 * ((np.sin(theta) / x_stddev) ** 2 + | ||
(np.cos(theta) / y_stddev) ** 2) | ||
|
||
da_dtheta = np.sin(theta) * np.cos(theta) * (1/y_stddev**2 - 1/x_stddev**2) | ||
da_dx_stddev = -np.cos(theta)**2/x_stddev**3 | ||
da_dy_stddev = -np.sin(theta)**2/y_stddev**3 | ||
db_dtheta = 0.5*np.cos(2*theta) * (1/x_stddev**2 - 1/y_stddev**2) | ||
db_dx_stddev = -np.cos(theta)*np.sin(theta)/x_stddev**3 | ||
db_dy_stddev = np.cos(theta)*np.sin(theta)/y_stddev**3 | ||
dc_dtheta = np.cos(theta)*np.sin(theta)*(1/x_stddev**2 - 1/y_stddev**2) | ||
dc_dx_stddev = -np.sin(theta)**2/x_stddev**3 | ||
dc_dy_stddev = -np.cos(theta)**2/y_stddev**3 | ||
|
||
d_A = np.exp(- a * (x - x_mean) ** 2 | ||
- b * (x - x_mean) * (y - y_mean) | ||
- c * (y - y_mean) ** 2) | ||
d_theta = amplitude * (-(x - x_mean) ** 2 * da_dtheta - (x - x_mean) * | ||
(y - y_mean) * db_dtheta - (y - y_mean) ** 2 * dc_dtheta) * d_A | ||
|
||
d_x_stddev = amplitude * (-(x - x_mean) ** 2 *da_dx_stddev - | ||
(x - x_mean) * (y - y_mean) * db_dx_stddev | ||
- (y - y_mean) ** 2 * dc_dx_stddev) * d_A | ||
d_y_stddev = amplitude * (-(x - x_mean) ** 2 *da_dy_stddev - | ||
(x - x_mean) * (y - y_mean) * db_dy_stddev | ||
- (y - y_mean) ** 2 * dc_dy_stddev) * d_A | ||
d_y_mean = amplitude * (+(x - x_mean) * b + 2 * (y - y_mean) * c) * d_A | ||
d_x_mean = amplitude * ((y - y_mean) * b + 2 * (x - x_mean) * a) * d_A | ||
return [d_A, d_x_mean, d_y_mean, d_x_stddev, d_y_stddev, d_theta] | ||
cost = np.cos(theta) | ||
sint = np.sin(theta) | ||
cost2 = np.cos(theta) ** 2 | ||
sint2 = np.sin(theta) ** 2 | ||
cos2t = np.cos(2. * theta) | ||
sin2t = np.sin(2. * theta) | ||
xstd2 = x_stddev ** 2 | ||
ystd2 = y_stddev ** 2 | ||
xstd3 = x_stddev ** 3 | ||
ystd3 = y_stddev ** 3 | ||
xdiff = x - x_mean | ||
ydiff = y - y_mean | ||
xdiff2 = xdiff ** 2 | ||
ydiff2 = ydiff ** 2 | ||
a = 0.5 * ((cost2 / xstd2) + (sint2 / ystd2)) | ||
b = 0.5 * (-(sin2t / xstd2) + (sin2t / ystd2)) | ||
c = 0.5 * ((sint2 / xstd2) + (cost2 / ystd2)) | ||
g = amplitude * np.exp(-((a * xdiff2) + (b * xdiff * ydiff) + | ||
(c * ydiff2))) | ||
da_dtheta = (sint * cost * ((1. / ystd2) - (1. / xstd2))) | ||
da_dx_stddev = -cost2 / xstd3 | ||
da_dy_stddev = -sint2 / ystd3 | ||
db_dtheta = (-cos2t / xstd2) + (cos2t / ystd2) | ||
db_dx_stddev = sin2t / xstd3 | ||
db_dy_stddev = -sin2t / ystd3 | ||
dc_dtheta = -da_dtheta | ||
dc_dx_stddev = -sint2 / xstd3 | ||
dc_dy_stddev = -cost2 / ystd3 | ||
dg_dA = g / amplitude | ||
dg_dx_mean = g * ((2. * a * xdiff) + (b * ydiff)) | ||
dg_dy_mean = g * ((b * xdiff) + (2. * c * ydiff)) | ||
dg_dx_stddev = g * (-(da_dx_stddev * xdiff2 + | ||
db_dx_stddev * xdiff * ydiff + | ||
dc_dx_stddev * ydiff2)) | ||
dg_dy_stddev = g * (-(da_dy_stddev * xdiff2 + | ||
db_dy_stddev * xdiff * ydiff + | ||
dc_dy_stddev * ydiff2)) | ||
dg_dtheta = g * (-(da_dtheta * xdiff2 + | ||
db_dtheta * xdiff * ydiff + | ||
dc_dtheta * ydiff2)) | ||
return [dg_dA, dg_dx_mean, dg_dy_mean, dg_dx_stddev, dg_dy_stddev, | ||
dg_dtheta] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I can do that. I suppose I should also save There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yes, definitely those too. At some point I still want to push for more efficient implementations of these functions, but for now a lot is gained simply by reusing intermediate results like those. |
||
|
||
|
||
class Shift(Model): | ||
|
@@ -423,7 +437,7 @@ class Linear1D(Parametric1DModel): | |
|
||
def __init__(self, slope, intercept, **constraints): | ||
super(Linear1D, self).__init__(slope=slope, intercept=intercept, | ||
**constraints) | ||
**constraints) | ||
|
||
@staticmethod | ||
def eval(x, slope, intercept): | ||
|
@@ -472,7 +486,7 @@ class Lorentz1D(Parametric1DModel): | |
|
||
def __init__(self, amplitude, x_0, fwhm, **constraints): | ||
super(Lorentz1D, self).__init__(amplitude=amplitude, x_0=x_0, | ||
fwhm=fwhm, **constraints) | ||
fwhm=fwhm, **constraints) | ||
|
||
@staticmethod | ||
def eval(x, amplitude, x_0, fwhm): | ||
|
@@ -738,7 +752,7 @@ def eval(x, amplitude, x_0, width): | |
|
||
return np.select([np.logical_and(x >= x_0 - width / 2., | ||
x <= x_0 + width / 2.)], | ||
[amplitude], 0) | ||
[amplitude], 0) | ||
|
||
@classmethod | ||
def fit_deriv(cls, x, amplitude, x_0, width): | ||
|
@@ -801,8 +815,10 @@ def __init__(self, amplitude, x_0, y_0, x_width, y_width, **constraints): | |
@staticmethod | ||
def eval(x, y, amplitude, x_0, y_0, x_width, y_width): | ||
"""Two dimensional Box model function""" | ||
x_range = np.logical_and(x >= x_0 - x_width / 2., x <= x_0 + x_width / 2.) | ||
y_range = np.logical_and(y >= y_0 - y_width / 2., y <= y_0 + y_width / 2.) | ||
x_range = np.logical_and(x >= x_0 - x_width / 2., | ||
x <= x_0 + x_width / 2.) | ||
y_range = np.logical_and(y >= y_0 - y_width / 2., | ||
y <= y_0 + y_width / 2.) | ||
return np.select([np.logical_and(x_range, y_range)], [amplitude], 0) | ||
|
||
|
||
|
@@ -889,7 +905,6 @@ def __init__(self, amplitude, x_0, y_0, R_0, slope, **constraints): | |
x_0=x_0, y_0=y_0, R_0=R_0, | ||
slope=slope, **constraints) | ||
|
||
|
||
@staticmethod | ||
def eval(x, y, amplitude, x_0, y_0, R_0, slope): | ||
"""Two dimensional Trapezoid Disk model function""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to find out if the
deriv
method is covered by the unit tests.Turns out it is, but the only way I was able to find this coverage information for this pull request was via the travis-ci log, which seems overly complicated:
https://travis-ci.org/astropy/astropy/jobs/18914850#L1843
https://coveralls.io/files/137268781#L229
@astrofrog Is there a better way of browsing to coverage information for astropy pull requests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cdeil - you can run:
or go directly to https://coveralls.io/r/astropy/astropy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the https://coveralls.io/r/astropy/astropy page just has the builds in order, so it's very hard to find the coverage report for a given pull request if the build isn't very recent, no?
(Am I missing something?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right yes - in that case there is no easy way. The issue numbers are listed on coveralls though, but I agree it'd be nice to have an easier way.