Skip to content

Commit

Permalink
Merge pull request #399 from tomasstolker/snr
Browse files Browse the repository at this point in the history
Nelder-Mead minimization in FalsePositiveModule and offset parameter
  • Loading branch information
Tomas Stolker committed Nov 18, 2019
2 parents cd80555 + ac68ebb commit be01191
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 27 deletions.
61 changes: 38 additions & 23 deletions pynpoint/processing/fluxposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,14 +494,15 @@ def __init__(self,
aperture: float = 0.1,
ignore: bool = False,
optimize: bool = False,
**kwargs: Union[float, Tuple[Tuple[float, float], Tuple[float, float]]]) -> None:
**kwargs) -> None:
"""
Parameters
----------
name_in : str
Unique name of the module instance.
image_in_tag : str
Tag of the database entry with the images that are read as input.
Tag of the database entry with the images that are read as input. The SNR/FPF is
calculated for each image in the dataset.
snr_out_tag : str
Tag of the database entry that is written as output. The output format is: (x position
(pix), y position (pix), separation (arcsec), position angle (deg), SNR, FPF). The
Expand All @@ -517,17 +518,17 @@ def __init__(self,
ignore : bool
Ignore the two neighboring apertures that may contain self-subtraction from the planet.
optimize : bool
Optimize the SNR. The aperture position is written in the history. The size of the
Optimize the SNR. The aperture position is stored in the `snr_out_tag`. The size of the
aperture is kept fixed.
Keyword arguments
-----------------
tolerance : float
The fractional tolerance on the position for the optimization to end. Default is set
to 1e-3.
bounds : tuple(tuple(float, float), tuple(float, float))
Boundaries (pix) for the horizontal and vertical offset with respect to the `position`.
The default is set to (-3, 3) for both directions.
The absolute tolerance on the position for the optimization to end. Default is set
to 0.01 (pix).
offset : float, None
Offset (pix) by which the aperture may deviate from ``position`` when
``optimize=True`` (default: None).
Returns
-------
Expand All @@ -538,12 +539,16 @@ def __init__(self,
if 'tolerance' in kwargs:
self.m_tolerance = kwargs['tolerance']
else:
self.m_tolerance = 1e-3
self.m_tolerance = 1e-2

if 'bounds' in kwargs:
self.m_bounds = kwargs['bounds']
if 'offset' in kwargs:
self.m_offset = kwargs['offset']
else:
self.m_bounds = ((-3., 3.), (-3., 3.))
self.m_offset = None

if 'bounds' in kwargs:
warnings.warn('The \'bounds\' keyword argument has been deprecated. Please use '
'\'offset\' instead (e.g. offset=3.0).', DeprecationWarning)

super(FalsePositiveModule, self).__init__(name_in)

Expand Down Expand Up @@ -571,11 +576,24 @@ def run(self) -> None:
def _snr_optimize(arg):
pos_x, pos_y = arg

_, _, snr, _ = false_alarm(image=image,
x_pos=pos_x,
y_pos=pos_y,
size=self.m_aperture,
ignore=self.m_ignore)
if self.m_offset is not None:
if pos_x < self.m_position[0] - self.m_offset or \
pos_x > self.m_position[0] + self.m_offset:
snr = 0.

elif pos_y < self.m_position[1] - self.m_offset or \
pos_y > self.m_position[1] + self.m_offset:
snr = 0.

else:
snr = None

if self.m_offset is None or snr is None:
_, _, snr, _ = false_alarm(image=image,
x_pos=pos_x,
y_pos=pos_y,
size=self.m_aperture,
ignore=self.m_ignore)

return -snr

Expand All @@ -587,10 +605,8 @@ def _snr_optimize(arg):

nimages = self.m_image_in_port.get_shape()[0]

bounds = ((self.m_position[0]+self.m_bounds[0][0], self.m_position[0]+self.m_bounds[0][1]),
(self.m_position[1]+self.m_bounds[1][0], self.m_position[1]+self.m_bounds[1][1]))

start_time = time.time()

for j in range(nimages):
progress(j, nimages, 'Calculating S/N and FPF...', start_time)

Expand All @@ -600,10 +616,9 @@ def _snr_optimize(arg):
if self.m_optimize:
result = minimize(fun=_snr_optimize,
x0=[self.m_position[0], self.m_position[1]],
method='SLSQP',
bounds=bounds,
method='Nelder-Mead',
tol=None,
options={'ftol': self.m_tolerance})
options={'xatol': self.m_tolerance, 'fatol': float('inf')})

_, _, snr, fpf = false_alarm(image=image,
x_pos=result.x[0],
Expand Down
32 changes: 28 additions & 4 deletions tests/test_processing/test_fluxposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 +204,45 @@ def test_false_positive(self):
module = FalsePositiveModule(position=(31., 49.),
aperture=0.1,
ignore=True,
name_in='false',
name_in='false1',
image_in_tag='res_mean',
snr_out_tag='snr_fpf')
snr_out_tag='snr_fpf1',
optimize=False)

self.pipeline.add_module(module)
self.pipeline.run_module('false')
self.pipeline.run_module('false1')

data = self.pipeline.get_data('snr_fpf')
data = self.pipeline.get_data('snr_fpf1')
assert np.allclose(data[0, 0], 31.0, rtol=limit, atol=0.)
assert np.allclose(data[0, 1], 49.0, rtol=limit, atol=0.)
assert np.allclose(data[0, 2], 0.513710034941892, rtol=limit, atol=0.)
assert np.allclose(data[0, 3], 93.01278750418334, rtol=limit, atol=0.)
assert np.allclose(data[0, 4], 7.333740467578795, rtol=limit, atol=0.)
assert np.allclose(data[0, 5], 4.5257622875993775e-06, rtol=limit, atol=0.)

def test_false_positive_optimize(self):

module = FalsePositiveModule(position=(31., 49.),
aperture=0.1,
ignore=True,
name_in='false2',
image_in_tag='res_mean',
snr_out_tag='snr_fpf2',
optimize=True,
offset=0.1,
tolerance=0.01)

self.pipeline.add_module(module)
self.pipeline.run_module('false2')

data = self.pipeline.get_data('snr_fpf2')
assert np.allclose(data[0, 0], 30.90615234375, rtol=limit, atol=0.)
assert np.allclose(data[0, 1], 49.0861328125, rtol=limit, atol=0.)
assert np.allclose(data[0, 2], 0.5161240306986961, rtol=limit, atol=0.)
assert np.allclose(data[0, 3], 92.74019185433872, rtol=limit, atol=0.)
assert np.allclose(data[0, 4], 7.831022605121996, rtol=limit, atol=0.)
assert np.allclose(data[0, 5], 2.3375921055608217e-06, rtol=limit, atol=0.)

def test_simplex_minimization_hessian(self):

module = SimplexMinimizationModule(name_in='simplex1',
Expand Down

0 comments on commit be01191

Please sign in to comment.