diff --git a/coolest/api/analysis.py b/coolest/api/analysis.py index 13b81a1..b6d0430 100644 --- a/coolest/api/analysis.py +++ b/coolest/api/analysis.py @@ -2,11 +2,14 @@ import numpy as np from astropy.coordinates import SkyCoord -import warnings +import logging +from skimage import measure from coolest.api.composable_models import * from coolest.api import util +# logging settings +logging.getLogger().setLevel(logging.INFO) class Analysis(object): """Handles computation of model-independent quantities @@ -63,7 +66,7 @@ def effective_einstein_radius(self, center=None, initial_guess=1, initial_delta_ Raises ------ - Warning + RuntimeError If the algorithm is running for more than 100 loops. """ if kwargs_selection is None: @@ -93,8 +96,7 @@ def loop_until_overshoot(r_Ein, delta, direction, runningtotal, total_pix): return np.nan, np.nan, 0, runningtotal, total_pix while (runningtotal-total_pix)*direction>0: if loopcount > max_loopcount: - raise Warning('Stuck in very long (possibly infinite) loop') - break + raise RuntimeError('Stuck in very long (possibly infinite) loop') if direction > 0: mask=only_between_r1r2(r_Ein, r_Ein+delta,r_grid) else: @@ -112,7 +114,7 @@ def loop_until_overshoot(r_Ein, delta, direction, runningtotal, total_pix): runningtotal=np.sum(kappa_image[mask]) total_pix=np.sum(mask) if runningtotal-total_pix < 0: - print('WARNING: kappa is sub-critical, Einstein radius undefined.') + logging.warning('kappa is sub-critical, Einstein radius undefined.') return np.nan, np.nan, 0, runningtotal, total_pix loopcount+=1 return r_Ein, delta, direction, runningtotal, total_pix @@ -220,7 +222,8 @@ def effective_radial_slope(self, r_eval=None, center=None, r_vec=np.linspace(0, def effective_radius_light(self, outer_radius=10, center=None, coordinates=None, initial_guess=1, initial_delta_pix=10, - n_iter=10, return_model=False, **kwargs_selection): + n_iter=10, return_model=False, return_accuracy=False, + **kwargs_selection): """Computes the effective radius of the 2D surface brightness profile, based on a definition similar to the half-light radius. @@ -234,13 +237,15 @@ def effective_radius_light(self, outer_radius=10, center=None, coordinates=None, Instance of a Coordinates object to be used for the computation. If None, will use an instance based on the Instrument, by default None initial_guess : int, optional - Initial guess for effective radius, by default 1 + Initial guess for effective radius in arcsecond, by default 1 initial_delta_pix : int, optional - Initial step size before shrinking in future iterations, by default 10 + Initial step size in pixels before shrinking in future iterations, by default 10 n_iter : int, optional Number of iterations, by default 5 return_model : bool, optional If True, also returns the surface brightness map used to comouted the radius. By default False. + return_accuracy : bool, optional + if True, return a rough estimate of accuracy as well, by default False Returns ------- @@ -254,64 +259,53 @@ def effective_radius_light(self, outer_radius=10, center=None, coordinates=None, """ if kwargs_selection is None: kwargs_selection = {} - light_model = ComposableLightModel(self.coolest, self.coolest_dir, **kwargs_selection) - # get an image of the convergence - if coordinates is None: - x, y = self.coordinates.pixel_coordinates - else: - x, y = coordinates.pixel_coordinates - light_image = light_model.evaluate_surface_brightness(x, y) - light_image[np.isnan(light_image)] = 0. - # import matplotlib.pyplot as plt - # plt.imshow(np.log10(light_image)) - # plt.show() + light_model = ComposableLightModel(self.coolest, self.coolest_dir, **kwargs_selection) # select a center if center is None: center_x, center_y = light_model.estimate_center() else: center_x, center_y = center + + # get an image of the convergence + if coordinates is None: + x, y = self.coordinates.pixel_coordinates + else: + x, y = coordinates.pixel_coordinates + # make sure to evaluate the profile such that it is centered on the image + x_ = x + center_x + y_ = y + center_y + light_image = light_model.evaluate_surface_brightness(x_, y_) + light_image[np.isnan(light_image)] = 0. #if limit of integration exceeds FoV, raise warning - x_FoV=self.coolest.observation.pixels.field_of_view_x - y_FoV=self.coolest.observation.pixels.field_of_view_y + if coordinates is None: + x_FoV = self.coolest.observation.pixels.field_of_view_x + y_FoV = self.coolest.observation.pixels.field_of_view_y + else: + x_FoV = (coordinates.extent[0], coordinates.extent[1]) + y_FoV = (coordinates.extent[2], coordinates.extent[3]) out_of_FoV=False - if center_x - outer_radius < x_FoV[0] or center_x + outer_radius > x_FoV[1]: + if outer_radius - center_x < x_FoV[0] or outer_radius + center_x > x_FoV[1]: out_of_FoV=True - if center_y - outer_radius < y_FoV[0] or center_y + outer_radius > y_FoV[1]: + if outer_radius - center_y < y_FoV[0] or outer_radius + center_y > y_FoV[1]: out_of_FoV=True if out_of_FoV is True: - warnings.warn("Warning: Outer limit of integration exceeds FoV; effective radius may not be accurate.") - - #initialize - grid_res=np.abs(x[0,0]-x[0,1]) - initial_delta=grid_res*initial_delta_pix #default inital step size is 10 pixels - r_grid=np.sqrt((x-center_x)**2+(y-center_y)**2) - total_light=np.sum(light_image[r_grid total_light/2: #move inward - direction=-1 - else: - return initial_guess - r_eff=initial_guess - delta=initial_delta - loopcount=0 - - for n in range(n_iter): #overshoots, turn around and backtrack at higher precision - while (total_light/2-cumulative_light)*direction>0: - if loopcount > 100: - raise Warning('Stuck in very long (possibly infinite) loop') - break - r_eff=r_eff+delta*direction - cumulative_light=np.sum(light_image[r_grid total_light/2: #move inward + direction=-1 + else: + return initial_guess + r_eff=initial_guess + delta=initial_delta + loopcount=0 + + for n in range(n_iter): #overshoots, turn around and backtrack at higher precision + while (total_light/2.-cumulative_light)*direction>0: + if loopcount > 100: + raise RuntimeError('Stuck in very long (possibly infinite) loop') + r_eff=r_eff+delta*direction + cumulative_light=np.sum(light_map[r_grid" ] @@ -204,27 +229,8 @@ } ], "source": [ - "# Capture the image for any further adjustments (it is a GetDistPlotter object)\n", - "colors = ['#E03424','#7FB6F5']\n", - "settings={\"ignore_rows\": 0.0,\"fine_bins_2D\":800,\"smooth_scale_2D\":0.5,\"mult_bias_correction_order\":5}\n", - "image = plot_corner(free_pars,\n", - " [coolest_2,coolest_1],\n", - " [dir_2,dir_1],\n", - " point_estimate_objs=[truth,truth2],\n", - " labels=labels,\n", - " chain_names=[\"Complex source\",\"Smooth source\"],\n", - " colors=colors,\n", - " subplot_size=2,\n", - " mc_samples_kwargs=settings)" + "g = param_plotter.plot_triangle_getdist(filled_contours=True, subplot_size=2)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62d1cbb3", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {