Passed
Push — master ( 573345...9597ff )
by Giacomo
06:15
created

FlatSkyProjection._oversample()   A

Complexity

Conditions 2

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 21
rs 9.9
c 0
b 0
f 0
cc 2
nop 2
1
from astropy.io import fits
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
introduced by
Unable to import 'astropy.io'
Loading history...
2
from astropy.wcs import WCS
0 ignored issues
show
introduced by
Unable to import 'astropy.wcs'
Loading history...
3
from astropy.wcs.utils import proj_plane_pixel_area
0 ignored issues
show
introduced by
Unable to import 'astropy.wcs.utils'
Loading history...
4
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
5
6
from util import cartesian
0 ignored issues
show
Coding Style introduced by
Relative import 'util', should be 'hawc_hal.util'
Loading history...
7
from psf_fast.sphere_dist import sphere_dist
0 ignored issues
show
Coding Style introduced by
Relative import 'psf_fast.sphere_dist', should be 'hawc_hal.psf_fast.sphere_dist'
Loading history...
8
9
10
_fits_header = """
0 ignored issues
show
Coding Style Naming introduced by
The name _fits_header does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
11
NAXIS   =                    2
12
NAXIS1  =                   %i
13
NAXIS2  =                   %i
14
CTYPE1  = 'RA---AIT'
15
CRPIX1  =                   %i
16
CRVAL1  =                   %s
17
CDELT1  =                  -%f
18
CUNIT1  = 'deg     '
19
CTYPE2  = 'DEC--AIT'
20
CRPIX2  =                   %i
21
CRVAL2  =                   %s
22
CDELT2  =                   %f
23
CUNIT2  = 'deg     '
24
COORDSYS= '%s'
25
"""
26
27
28
def _get_header(ra, dec, pixel_size, coordsys, h, w):
0 ignored issues
show
Coding Style Naming introduced by
The name ra does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
The name h does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
The name w does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
best-practice introduced by
Too many arguments (6/5)
Loading history...
29
30
    assert 0 <= ra <= 360
31
32
    header = fits.Header.fromstring(_fits_header % (h, w,
33
                                                    h / 2, ra, pixel_size,
34
                                                    w / 2, dec, pixel_size,
35
                                                    coordsys),
36
                                    sep='\n')
37
38
    return header
39
40
41
def _get_all_ra_dec(input_wcs, h, w):
0 ignored issues
show
Coding Style Naming introduced by
The name h does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
The name w does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
42
43
    # An array of all the possible permutation of (i,j) for i=0..999 and j=0..999
44
45
    xx = np.arange(0.5, h + 0.5, 1, dtype=np.int16)
0 ignored issues
show
Coding Style Naming introduced by
The name xx does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
46
    yy = np.arange(0.5, w + 0.5, 1, dtype=np.int16)
0 ignored issues
show
Coding Style Naming introduced by
The name yy does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
47
48
    _ij_grid = cartesian((xx,
49
                          yy))
50
51
    # Convert pixel coordinates to world coordinates
52
    world = input_wcs.all_pix2world(_ij_grid, 0, ra_dec_order=True)
53
54
    return world[:, 0], world[:, 1]
55
56
57
class FlatSkyProjection(object):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
best-practice introduced by
Too many instance attributes (12/7)
Loading history...
58
59
    def __init__(self, ra_center, dec_center, pixel_size_deg, npix_height, npix_width, oversample=True):
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
best-practice introduced by
Too many arguments (7/5)
Loading history...
60
61
        assert npix_height % 2 == 0, "Number of height pixels must be even"
62
        assert npix_width % 2 == 0, "Number of width pixels must be even"
63
64
        if isinstance(npix_height, float):
65
66
            assert npix_height.is_integer(), "This is a bug"
67
68
        if isinstance(npix_width, float):
69
70
            assert npix_width.is_integer(), "This is a bug"
71
72
        self._npix_height = int(npix_height)
73
        self._npix_width = int(npix_width)
74
75
        assert 0 <= ra_center <= 360.0, "Right Ascension must be between 0 and 360"
76
        assert -90.0 <= dec_center <= 90.0, "Declination must be between -90.0 and 90.0"
77
78
        self._ra_center = float(ra_center)
79
        self._dec_center = float(dec_center)
80
81
        self._pixel_size_deg = float(pixel_size_deg)
82
83
        # Build projection, i.e., a World Coordinate System object
84
85
        self._wcs = WCS(_get_header(ra_center, dec_center, pixel_size_deg, 'icrs', npix_height, npix_width))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (108/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
86
87
        # Pre-compute all R.A., Decs
88
        self._ras, self._decs = _get_all_ra_dec(self._wcs, npix_height, npix_width)
89
90
        # Make sure we have the right amount of coordinates
91
        assert self._ras.shape[0] == self._decs.shape[0]
92
        assert self._ras.shape[0] == npix_width * npix_height
93
94
        # Pre-compute pixel area
95
        self._pixel_area= proj_plane_pixel_area(self._wcs)
0 ignored issues
show
Coding Style introduced by
Exactly one space required before assignment
Loading history...
96
97
        # Pre-compute an oversampled version to be used for PSF integration
98
        if oversample and pixel_size_deg > 0.025:
99
100
            self._oversampled, self._oversample_factor = self._oversample(new_pixel_size=0.025)
101
102
        else:
103
104
            self._oversampled = self
105
            self._oversample_factor = 1
106
107
        # Cache for angular distances from a point (see get_spherical_distances_from)
108
        self._distance_cache = {}
109
110
    def _oversample(self, new_pixel_size):
111
        """Return a new instance oversampled by the provided factor"""
112
113
        # Compute the oversampling factor (as a float because we need it for the division down)
114
        factor = float(np.ceil(self._pixel_size_deg / new_pixel_size))
115
116
        if factor <= 1:
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
117
118
            # The projection is already with a smaller pixel size than the oversampled version
119
            # No need to oversample
120
            return self, 1
121
122
        else:
123
124
            new_fp = FlatSkyProjection(self._ra_center, self._dec_center,
125
                                       self._pixel_size_deg / factor,
126
                                       self._npix_height * factor,
127
                                       self._npix_width * factor,
128
                                       oversample=False)
129
130
            return new_fp, int(factor)
131
132
    @property
133
    def oversampled(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
134
        return self._oversampled
135
136
    @property
137
    def oversample_factor(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
138
        return self._oversample_factor
139
140
    @property
141
    def ras(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
142
        return self._ras
143
144
    @property
145
    def decs(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
146
        return self._decs
147
148
    @property
149
    def ra_center(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
150
        return self._ra_center
151
152
    @property
153
    def dec_center(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
154
        return self._dec_center
155
156
    @property
157
    def pixel_size(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
158
        return self._pixel_size_deg
159
160
    @property
161
    def wcs(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
162
        return self._wcs
163
164
    @property
165
    def npix_height(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
166
        return self._npix_height
167
168
    @property
169
    def npix_width(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
170
        return self._npix_width
171
172
    @property
173
    def project_plane_pixel_area(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
174
        return self._pixel_area
175
176
    def get_spherical_distances_from(self, ra, dec, cutout_radius):
0 ignored issues
show
Coding Style Naming introduced by
The name ra does not conform to the argument naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
177
        """
178
        Returns the distances for all points in this grid from the given point
179
180
        :param ra:
181
        :param dec:
182
        :param cutout_radius: do not consider elements beyond this radius (NOTE: we use a planar approximation on
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
183
        purpose, to make things fast, so the cut is not precise)
184
        :return: (angular distances of selected points from (ra, dec), selection indexes)
185
        """
186
187
        # This is typically used sequentially on different energy bins, so we cache the result and re-use it
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (108/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
188
        # if we already computed it
189
190
        key = (ra, dec, cutout_radius, self.ras.shape[0], self.decs.shape[0])
191
192
        if key not in self._distance_cache:
193
194
            # In order to gain speed, we use a planar approximation (instead of using the harversine formula we assume
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (118/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
195
            # plane geometry). This gets more and more unprecise the large the cutout radius, but we do not care here
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
196
197
            selection_idx = (((ra - self.ras)**2 + (dec - self.decs)**2) <= (1.2*cutout_radius)**2)  # type: np.ndarray
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (119/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
198
199
            ds = sphere_dist(ra, dec, self.ras[selection_idx], self.decs[selection_idx])
0 ignored issues
show
Coding Style Naming introduced by
The name ds does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
200
201
            # Refine selection by putting to False all elements in the mask at a distance larger than the cutout
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (112/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
202
            # radius
203
            fine_selection_idx = (ds <= cutout_radius)
204
            selection_idx[selection_idx.nonzero()[0][~fine_selection_idx]] = False
205
206
            # This is to make sure we only keep cached the last result, and the dictionary does not grow indefinitely
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (117/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
207
            self._distance_cache = {}
208
209
            self._distance_cache[key] = (ds[fine_selection_idx], selection_idx)
210
211
        return self._distance_cache[key]
212
0 ignored issues
show
coding-style introduced by
Trailing newlines
Loading history...
213