11import logging
22
3- import numpy
3+ import numpy as np
44from math import degrees , sqrt , sin , pi , cos
5- from dataclasses import dataclass
5+ from dataclasses import dataclass , field
6+ from sourcefinder .utils import is_valid_beam_tuple
67from sourcefinder .utility .coordinates import WCS
8+ from sourcefinder .config import ImgConf
9+ from typing import Optional , cast
710
811logger = logging .getLogger (__name__ )
912
@@ -16,7 +19,7 @@ class DataAccessor:
1619 Data accessors provide a uniform way for the ImageData class (i.e.,
1720 generic image representation) to access the various ways in which
1821 images may be stored (FITS files, arrays in memory, potentially HDF5,
19- etc).
22+ etc. ).
2023
2124 This class cannot be instantiated directly, but should be subclassed
2225 and the abstract properties provided. Note that all abstract
@@ -66,17 +69,26 @@ class DataAccessor:
6669 provides key info in a simple dict format.
6770 """
6871
69- beam : tuple
7072 centre_ra : float
7173 centre_decl : float
72- data : numpy .ndarray
74+ data : np .ndarray
7375 freq_bw : float
7476 freq_eff : float
7577 pixelsize : tuple
7678 tau_time : float
7779 taustart_ts : float
7880 url : str
7981 wcs : WCS
82+ beam : Optional [tuple [float , float , float ]] = field (default = None )
83+ conf : Optional [ImgConf ] = field (default = None , repr = False )
84+
85+ def __post_init__ (self ):
86+ if self .conf is not None :
87+ beam_tuple = (self .conf .bmaj , self .conf .bmin , self .conf .bpa )
88+ if is_valid_beam_tuple (beam_tuple ):
89+ deltax , deltay = self .pixelsize
90+ self .beam = DataAccessor .degrees2pixels (* beam_tuple ,
91+ deltax , deltay )
8092
8193 def extract_metadata (self ) -> dict :
8294 """
@@ -94,22 +106,30 @@ def extract_metadata(self) -> dict:
94106 A dictionary containing key-value pairs of class attributes
95107 formatted for database storage.
96108 """
97- return {
109+ metadata = {
98110 'tau_time' : self .tau_time ,
99111 'freq_eff' : self .freq_eff ,
100112 'freq_bw' : self .freq_bw ,
101113 'taustart_ts' : self .taustart_ts ,
102114 'url' : self .url ,
103- 'beam_smaj_pix' : self .beam [0 ],
104- 'beam_smin_pix' : self .beam [1 ],
105- 'beam_pa_rad' : self .beam [2 ],
106115 'centre_ra' : self .centre_ra ,
107116 'centre_decl' : self .centre_decl ,
108117 'deltax' : self .pixelsize [0 ],
109118 'deltay' : self .pixelsize [1 ],
110119 }
111120
112- def parse_pixelsize (self ):
121+
122+ if is_valid_beam_tuple (self .beam ):
123+ beam = cast (tuple [float , float , float ], self .beam )
124+ metadata .update ({
125+ 'beam_smaj_pix' : beam [0 ],
126+ 'beam_smin_pix' : beam [1 ],
127+ 'beam_pa_rad' : beam [2 ],
128+ })
129+
130+ return metadata
131+
132+ def parse_pixelsize (self ) -> tuple [float , float ]:
113133 """
114134 Returns
115135 -------
@@ -141,7 +161,8 @@ def parse_pixelsize(self):
141161 return deltax , deltay
142162
143163 @staticmethod
144- def degrees2pixels (bmaj , bmin , bpa , deltax , deltay ):
164+ def degrees2pixels (bmaj , bmin , bpa , deltax , deltay ) -> (
165+ tuple )[float , float , float ]:
145166 """
146167 Convert beam in degrees to beam in pixels and radians.
147168 For example, FITS beam parameters are in degrees.
@@ -161,12 +182,14 @@ def degrees2pixels(bmaj, bmin, bpa, deltax, deltay):
161182
162183 Returns
163184 -------
164- semimaj : float
165- Beam semi-major axis in pixels.
166- semimin : float
167- Beam semi-minor axis in pixels.
168- theta : float
169- Beam position angle in radians.
185+ tuple
186+ A tuple containing:
187+ - semimaj : float
188+ Beam semi-major axis in pixels.
189+ - semimin : float
190+ Beam semi-minor axis in pixels.
191+ - theta : float
192+ Beam position angle in radians.
170193 """
171194 theta = pi * bpa / 180
172195 semimaj = (bmaj / 2. ) * (sqrt (
0 commit comments