Skip to content

Commit 2d1f447

Browse files
authored
Merge pull request #160 from discsim/log_normal
Log-normal fits
2 parents 62c3e61 + 45dff44 commit 2d1f447

19 files changed

+2698
-642
lines changed

HISTORY.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,42 @@
33
Changelog
44
+++++++++
55

6+
v.1.2.0
7+
+++++++
8+
*Introduction of log-normal fits, large amount of code refactoring to support both 'Gaussian' and 'LogNormal' methods*
9+
10+
- default_parameters.json, parameter_descriptions.json:
11+
- Adds parameters: 'rescale_flux', 'method'
12+
- debris_fitters.py
13+
- Adds support for fitting optically thin but geometrically thick disks with a known Gaussian scale height.
14+
- filter.py:
15+
- New module that now hosts the routine for optimizing for power spectrum priors, 'CriticalFilter'
16+
- fit.py:
17+
- Adds ability to run either a standard or log-normal fit
18+
- geometry.py:
19+
- Adds routine to rescale the total flux according to the source geometry, 'rescale_total_flux'
20+
- Adds 'rescale_factor' property to 'SourceGeometry'
21+
- Adds the option to keep all three Fourier components (u,v,w) when deprojecting
22+
- minimizer.py:
23+
- New module that hosts routines for solving non-linear minimization problems: 'BaseLineSearch', 'LineSearch', 'MinimizeNewton'
24+
- radial_fitters.py:
25+
- Code refactoring:
26+
* Removes '_HankelRegressor' class
27+
* Adds 'FrankGaussianFit' and 'FrankLogNormalFit' classes
28+
* Adds 'FrankRadialFit' class
29+
* Moves some core functionalities to 'frank.filter' and 'frank.statistical_models'
30+
- Adds 'MAP', 'I', 'info' properties, and 'assume_optically_thick' parameter, to 'FrankRadialFit'
31+
- statistical_models.py:
32+
- New module that now hosts 'GaussianModel' class (containing much of the functionality of the now deprecated '_HankelRegressor'), and adds analogous 'LogNormalMAPModel' class
33+
- Adds a VisibilityMapping that abstracts the mapping between the brightness profile and visibilities. Handles optically thick (default), optically thin, and debris disk models.
34+
- tests.py:
35+
- Adds test for a log-normal fit
36+
- Docs:
37+
- Updates API
38+
- Miscellaneous:
39+
- Minor bug and typo fixes
40+
41+
642
v.1.1.0
743
+++++++
844

docs/py_API.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,27 @@ the deprojected visibilities.
2525
.. autoclass:: frank.radial_fitters.FrankFitter
2626
:members: fit, MAP_solution, MAP_spectrum, MAP_spectrum_covariance, r, Rmax, q, Qmax, size, geometry
2727

28-
.. autoclass:: frank.radial_fitters._HankelRegressor
29-
:members: mean, covariance, power_spectrum, r, q, Rmax, Qmax, size, geometry, predict, predict_deprojected, log_likelihood, solve_non_negative
28+
.. autoclass:: frank.radial_fitters.FrankRadialFit
29+
:members: I, MAP, r, q, Rmax, Qmax, size, geometry, predict, predict_deprojected
30+
31+
.. autoclass:: frank.radial_fitters.FrankGaussianFit
32+
:members: I, mean, MAP, covariance, power_spectrum, r, q, Rmax, Qmax, size, geometry, predict, predict_deprojected, log_likelihood, solve_non_negative
33+
34+
.. autoclass:: frank.radial_fitters.FrankLogNormalFit
35+
:members: I, MAP, covariance, power_spectrum, r, q, Rmax, Qmax, size, geometry, predict, predict_deprojected, log_likelihood
36+
37+
.. autoclass:: frank.debris_fitters.FrankDebrisFitter
38+
:members: fit, MAP_solution, MAP_spectrum, MAP_spectrum_covariance, r, Rmax, q, Qmax, size, geometry
39+
3040

3141
Utility functions and classes
3242
-----------------------------
3343

3444
These are some useful functions and classes for various aspects of fitting and analysis.
3545

46+
.. autoclass:: frank.hankel.DiscreteHankelTransform
47+
:members: r, Rmax, q, Qmax, size, order, transform, coefficients
48+
3649
.. autofunction:: frank.utilities.arcsec_baseline
3750

3851
.. autofunction:: frank.utilities.convolve_profile
@@ -43,6 +56,8 @@ These are some useful functions and classes for various aspects of fitting and a
4356

4457
.. autofunction:: frank.utilities.estimate_weights
4558

59+
.. autofunction:: frank.utilities.make_image
60+
4661
.. autofunction:: frank.utilities.normalize_uv
4762

4863
.. autofunction:: frank.utilities.sweep_profile

docs/tutorials/fitting_procedure.ipynb

Lines changed: 17 additions & 10 deletions
Large diffs are not rendered by default.

docs/tutorials/model_limitations.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ is useful to assess and potentially suppress this behavior.
1919
Allowed regions of negative brightness
2020
--------------------------------------
2121
The fitted brightness profile can have negative regions corresponding to spatial scales un- or underconstrained by the visibilities.
22-
You can perform a fit in which the solution is forced to be positive (given the maximum a posteriori power spectrum) by using the `solve_non_negative <../py_API.rst#frank.radial_fitters._HankelRegressor.solve_non_negative>`_ method provided by the solution returned by `FrankFitter` (if running frank from the terminal, set `hyperparameters : nonnegative` to `true` in your parameter file).
22+
You can perform a fit in which the solution is forced to be positive (given the maximum a posteriori power spectrum) by using the `solve_non_negative <../py_API.rst#frank.radial_fitters.FrankGaussianFit.solve_non_negative>`_ method provided by the solution returned by `FrankFitter` (if running frank from the terminal, set `hyperparameters : nonnegative` to `true` in your parameter file).
2323
In tests we've seen the effect on the recovered brightness profile to typically be localized to the regions of negative flux,
2424
with otherwise minor differences.
2525
Since enforcing the profile to be non-negative requires some extrapolation beyond the data's longest baseline,

frank/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
# You should have received a copy of the GNU General Public License
1717
# along with this program. If not, see <https://www.gnu.org/licenses/>
1818
#
19-
__version__ = "1.1.0"
19+
__version__ = "1.2.0"
2020

2121
from frank import constants
2222
from frank import geometry
2323
from frank import hankel
2424
from frank import io
2525
from frank import radial_fitters
26+
from frank import debris_fitters
2627
from frank import utilities
2728

2829
def enable_logging(log_file=None):

frank/debris_fitters.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Frankenstein: 1D disc brightness profile reconstruction from Fourier data
2+
# using non-parametric Gaussian Processes
3+
#
4+
# Copyright (C) 2019-2020 R. Booth, J. Jennings, M. Tazzari
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
9+
# the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with this program. If not, see <https://www.gnu.org/licenses/>
19+
#
20+
"""This module contains methods for fitting a radial brightness profile to a set
21+
of deprojected visibities. Routines in this file assume that the emission is
22+
optically thin with a Gaussian vertical structure.
23+
"""
24+
import abc
25+
from collections import defaultdict
26+
import logging
27+
import numpy as np
28+
29+
from frank.radial_fitters import FourierBesselFitter, FrankFitter
30+
31+
class FourierBesselDebrisFitter(FourierBesselFitter):
32+
"""
33+
Fourier-Bessel series optically-thin model for fitting visibilities.
34+
35+
The brightness model is :math:`I(R, z) = I(R) exp(-z^2/2H(R)^2)`, where
36+
:math:`H(R)` is the (known) scale-height.
37+
38+
Parameters
39+
----------
40+
Rmax : float, unit = arcsec
41+
Radius of support for the functions to transform, i.e.,
42+
f(r) = 0 for R >= Rmax
43+
N : int
44+
Number of collocation points
45+
geometry : SourceGeometry object
46+
Geometry used to deproject the visibilities before fitting
47+
scale_height : function R --> H
48+
Specifies the thickness of disc as a function of radius. Both
49+
units should be in arcsec.
50+
nu : int, default = 0
51+
Order of the discrete Hankel transform (DHT)
52+
block_data : bool, default = True
53+
Large temporary matrices are needed to set up the data. If block_data
54+
is True, we avoid this, limiting the memory requirement to block_size
55+
elements.
56+
block_size : int, default = 10**5
57+
Size of the matrices if blocking is used
58+
verbose : bool, default = False
59+
Whether to print notification messages
60+
"""
61+
62+
def __init__(self, Rmax, N, geometry, scale_height, nu=0, block_data=True,
63+
block_size=10 ** 5, verbose=True):
64+
65+
# All functionality is provided by the base class.
66+
# FourierBesselDebrisFitter is just a sub-set of FourierBesselFitter
67+
super(FourierBesselDebrisFitter, self).__init__(
68+
Rmax, N, geometry, nu=nu, block_data=block_data,
69+
assume_optically_thick=False, scale_height=scale_height,
70+
block_size=block_size, verbose=verbose
71+
)
72+
73+
class FrankDebrisFitter(FrankFitter):
74+
"""
75+
Fit a Gaussian process model using the Discrete Hankel Transform of
76+
Baddour & Chouinard (2015).
77+
78+
The brightness model is :math:`I(R, z) = I(R) exp(-z^2/2H(R)^2)`, where
79+
:math:`H(R)` is the (known) scale-height.
80+
81+
The GP model is based upon Oppermann et al. (2013), which use a maximum
82+
a posteriori estimate for the power spectrum as the GP prior for the
83+
real-space coefficients.
84+
85+
Parameters
86+
----------
87+
Rmax : float, unit = arcsec
88+
Radius of support for the functions to transform, i.e., f(r) = 0 for
89+
R >= Rmax.
90+
N : int
91+
Number of collaction points
92+
geometry : SourceGeometry object
93+
Geometry used to deproject the visibilities before fitting
94+
scale_height : function R --> H
95+
Specifies the thickness of disc as a function of radius. Both
96+
units should be in arcsec.
97+
nu : int, default = 0
98+
Order of the discrete Hankel transform, given by J_nu(r)
99+
block_data : bool, default = True
100+
Large temporary matrices are needed to set up the data. If block_data
101+
is True, we avoid this, limiting the memory requirement to block_size
102+
elements
103+
block_size : int, default = 10**5
104+
Size of the matrices if blocking is used
105+
alpha : float >= 1, default = 1.05
106+
Order parameter of the inverse gamma prior for the power spectrum
107+
coefficients
108+
p_0 : float >= 0, default = None, unit=Jy^2
109+
Scale parameter of the inverse gamma prior for the power spectrum
110+
coefficients. If not provided p_0 = 1e-15 (method="Normal") or
111+
1e-35 (method="LogNormal") will be used.
112+
weights_smooth : float >= 0, default = 1e-4
113+
Spectral smoothness prior parameter. Zero is no smoothness prior
114+
tol : float > 0, default = 1e-3
115+
Tolerence for convergence of the power spectrum iteration
116+
method : string, default="Normal"
117+
Model used for the brightness reconstrution. This must be one of
118+
"Normal" of "LogNormal".
119+
I_scale : float, default = 1e5, unit= Jy/Sr
120+
Brightness scale. Only used in the LogNormal model. Notet the
121+
LogNormal model produces I(Rmax) = I_scale.
122+
max_iter: int, default = 2000
123+
Maximum number of fit iterations
124+
check_qbounds: bool, default = True
125+
Whether to check if the first (last) collocation point is smaller
126+
(larger) than the shortest (longest) deprojected baseline in the dataset
127+
store_iteration_diagnostics: bool, default = False
128+
Whether to store the power spectrum parameters and brightness profile
129+
for each fit iteration
130+
verbose:
131+
Whether to print notification messages
132+
133+
References
134+
----------
135+
Baddour & Chouinard (2015)
136+
DOI: https://doi.org/10.1364/JOSAA.32.000611
137+
Oppermann et al. (2013)
138+
DOI: https://doi.org/10.1103/PhysRevE.87.032136
139+
"""
140+
141+
def __init__(self, Rmax, N, geometry, scale_height, nu=0, block_data=True,
142+
block_size=10 ** 5, alpha=1.05, p_0=None, weights_smooth=1e-4,
143+
tol=1e-3, method='Normal', I_scale=1e5, max_iter=2000, check_qbounds=True,
144+
store_iteration_diagnostics=False, verbose=True):
145+
146+
# All functionality is provided by the base class. FrankDebrisFitter is just a
147+
# sub-set of FrankFitter
148+
super(FrankDebrisFitter, self).__init__(
149+
Rmax, N, geometry, nu=nu, block_data=block_data,
150+
block_size=block_size, alpha=alpha, p_0=p_0, weights_smooth=weights_smooth,
151+
tol=tol, method=method, I_scale=I_scale, max_iter=max_iter,
152+
check_qbounds=check_qbounds, store_iteration_diagnostics=store_iteration_diagnostics,
153+
assume_optically_thick=False, scale_height=scale_height, verbose=verbose)

frank/default_parameters.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"inc" : 0.0,
2626
"pa" : 0.0,
2727
"dra" : 0.0,
28-
"ddec" : 0.0
28+
"ddec" : 0.0,
29+
"rescale_flux" : true
2930
},
3031

3132
"hyperparameters" : {
@@ -36,7 +37,8 @@
3637
"wsmooth" : 1e-4,
3738
"iter_tol" : 1e-3,
3839
"max_iter" : 2000,
39-
"nonnegative" : false
40+
"nonnegative" : false,
41+
"method" : "Normal"
4042
},
4143

4244
"plotting" : {

0 commit comments

Comments
 (0)