class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, non_linear_class=af.MultiNest): super().__init__(paths=paths, non_linear_class=non_linear_class) self.profiles = profiles def run(self, dataset: Dataset, mask): analysis = self.make_analysis(dataset=dataset, mask=mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask): masked_dataset = MaskedDataset(dataset=dataset, mask=mask) return Analysis(masked_dataset=masked_dataset, image_path=self.optimizer.paths.image_path) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT): super().__init__(paths=paths, non_linear_class=non_linear_class) self.profiles = profiles self.transformer_class = transformer_class def run(self, dataset: Dataset, xy_mask): analysis = self.make_analysis( dataset=dataset, xy_mask=xy_mask ) result = self.run_analysis(analysis=analysis) return self.make_result( result=result, analysis=analysis ) def make_analysis(self, dataset, xy_mask): masked_dataset = MaskedDataset( dataset=dataset, xy_mask=xy_mask ) transformers = [] for i in range(masked_dataset.uv_wavelengths.shape[0]): transformers.append( self.transformer_class( uv_wavelengths=masked_dataset.uv_wavelengths[i], grid=masked_dataset.grid_3d.grid_2d.in_radians ) ) return Analysis( masked_dataset=masked_dataset, transformers=transformers, image_path=self.optimizer.paths.image_path ) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, non_linear_class=af.MultiNest): super().__init__(paths=paths, non_linear_class=non_linear_class) self.profiles = profiles def run(self, dataset: Spectrum): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset: aa.Imaging The dataset fitted by the phase, which in this case is a PyAutoArray imaging object. Returns ------- result: AbstractPhase.Result A result object comprising the best fit model. """ analysis = self.make_analysis(dataset=dataset) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset): """ Create an Analysis object, which creates the dataset and contains the functions which perform the fit. Parameters ---------- dataset: aa.Imaging The dataset fitted by the phase, which in this case is a PyAutoArray imaging object. Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit likelihood for a given model instance. """ return Analysis(dataset=dataset, dimensions=self.model.prior_count, visualize_path=self.optimizer.paths.image_path) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output )
class Phase(af.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Result = Result @af.convert_paths def __init__(self, paths, *, galaxies, self_calibration=False, non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT): super().__init__(paths=paths, non_linear_class=non_linear_class) self.galaxies = galaxies self.transformer_class = transformer_class self.self_calibration = self_calibration @property def phase_folders(self): return self.optimizer.phase_folders def run(self, dataset: Dataset, xy_mask): analysis = self.make_analysis(dataset=dataset, xy_mask=xy_mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, xy_mask): masked_dataset = MaskedDataset(dataset=dataset, xy_mask=xy_mask) transformer = self.transformer_class( uv_wavelengths=masked_dataset.uv_wavelengths, grid=masked_dataset.grid.in_radians) return Analysis(masked_dataset=masked_dataset, transformer=transformer, self_calibration=self.self_calibration, image_path=self.optimizer.paths.image_path) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class PhaseGalaxy(abstract.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Analysis = Analysis def __init__( self, phase_name, search, folders=tuple(), galaxies=None, use_image=False, use_convergence=False, use_potential=False, use_deflections=False, sub_size=2, pixel_scales_interp=None, cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear search to try to fit models and hyper_galaxies passed to it. Parameters ---------- search: class The class of a non_linear search sub_size: int The side length of the subgrid """ super(PhaseGalaxy, self).__init__(phase_name=phase_name, folders=folders, search=search) self.cosmology = cosmology self.use_image = use_image self.use_convergence = use_convergence self.use_potential = use_potential self.use_deflections = use_deflections self.galaxies = galaxies self.sub_size = sub_size self.pixel_scales_interp = pixel_scales_interp def run(self, galaxy_data, mask, info=None, results=None): """ Run this phase. Parameters ---------- galaxy_data mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_galaxies. """ analysis = self.make_analysis(galaxy_data=galaxy_data, results=results, mask=mask) self.save_metadata(galaxy_data.name) self.model = self.model.populate(results) result = self.run_analysis(analysis=analysis, info=info, pickle_files=pickle_files) return self.make_result(result, analysis) def make_analysis(self, galaxy_data, mask, results=None): """ Create an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- galaxy_data mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens: Analysis An lens object that the non-linear search calls to determine the fit of a set of values """ if self.use_image or self.use_convergence or self.use_potential: galaxy_data = masked_galaxy_data.MaskedGalaxyDataset( galaxy_data=galaxy_data[0], mask=mask, pixel_scales_interp=self.pixel_scales_interp, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=self.use_deflections, use_deflections_x=self.use_deflections, ) return AnalysisSingle( galaxy_data=galaxy_data, cosmology=self.cosmology, image_path=self.search.paths.image_path, results=results, ) elif self.use_deflections: galaxy_data_y = masked_galaxy_data.MaskedGalaxyDataset( galaxy_data=galaxy_data[0], mask=mask, pixel_scales_interp=self.pixel_scales_interp, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=self.use_deflections, use_deflections_x=False, ) galaxy_data_x = masked_galaxy_data.MaskedGalaxyDataset( galaxy_data=galaxy_data[1], mask=mask, pixel_scales_interp=self.pixel_scales_interp, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=False, use_deflections_x=self.use_deflections, ) return AnalysisDeflections( galaxy_data_y=galaxy_data_y, galaxy_data_x=galaxy_data_x, cosmology=self.cosmology, image_path=self.search.paths.image_path, results=results, )
class PhaseImaging(PhaseData): galaxies = af.PhaseProperty("galaxies") hyper_image_sky = af.PhaseProperty("hyper_image_sky") hyper_background_noise = af.PhaseProperty("hyper_background_noise") Analysis = Analysis Result = Result def __init__( self, phase_name, phase_folders=tuple(), galaxies=None, hyper_image_sky=None, hyper_background_noise=None, optimizer_class=af.MultiNest, cosmology=cosmo.Planck15, sub_size=2, signal_to_noise_limit=None, bin_up_factor=None, psf_shape=None, positions_threshold=None, mask_function=None, inner_mask_radii=None, pixel_scale_interpolation_grid=None, pixel_scale_binned_cluster_grid=None, inversion_uses_border=True, inversion_pixel_limit=None, auto_link_priors=False, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer sub_size: int The side length of the subgrid pixel_scale_binned_cluster_grid : float or None If *True*, the hyper_galaxies image used to generate the cluster'grids weight map will be binned \ up to this higher pixel scale to speed up the KMeans clustering algorithm. """ phase_tag = phase_tagging.phase_tag_from_phase_settings( sub_size=sub_size, signal_to_noise_limit=signal_to_noise_limit, bin_up_factor=bin_up_factor, psf_shape=psf_shape, positions_threshold=positions_threshold, inner_mask_radii=inner_mask_radii, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, pixel_scale_binned_cluster_grid=pixel_scale_binned_cluster_grid, ) super().__init__( phase_name=phase_name, phase_tag=phase_tag, phase_folders=phase_folders, galaxies=galaxies, optimizer_class=optimizer_class, cosmology=cosmology, auto_link_priors=auto_link_priors, ) self.hyper_image_sky = hyper_image_sky self.hyper_background_noise = hyper_background_noise self.hyper_noise_map_max = af.conf.instance.general.get( "hyper", "hyper_noise_map_max", float) self.is_hyper_phase = False self.meta_data_fit = MetaImagingFit( variable=self.variable, bin_up_factor=bin_up_factor, psf_shape=psf_shape, sub_size=sub_size, signal_to_noise_limit=signal_to_noise_limit, positions_threshold=positions_threshold, mask_function=mask_function, inner_mask_radii=inner_mask_radii, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, pixel_scale_binned_cluster_grid=pixel_scale_binned_cluster_grid, inversion_uses_border=inversion_uses_border, inversion_pixel_limit=inversion_pixel_limit, ) # noinspection PyMethodMayBeStatic,PyUnusedLocal def modify_image(self, image, results): """ Customize an lens_data. e.g. removing lens light. Parameters ---------- image: scaled_array.ScaledSquarePixelArray An lens_data that has been masked results: autofit.tools.pipeline.ResultsCollection The result of the previous lens Returns ------- lens_data: scaled_array.ScaledSquarePixelArray The modified image (not changed by default) """ return image def make_analysis(self, data, results=None, mask=None, positions=None): """ Create an lens object. Also calls the prior passing and lens_data modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline data: im.Imaging An lens_data that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ self.meta_data_fit.variable = self.variable modified_image = self.modify_image( image=data.image, results=results, ) lens_imaging_data = self.meta_data_fit.data_fit_from( data=data, mask=mask, positions=positions, results=results, modified_image=modified_image) self.output_phase_info() analysis = self.Analysis( lens_imaging_data=lens_imaging_data, cosmology=self.cosmology, image_path=self.optimizer.image_path, results=results, ) return analysis def output_phase_info(self): file_phase_info = "{}/{}".format(self.optimizer.phase_output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.optimizer).__name__)) phase_info.write("Sub-grid size = {} \n".format( self.meta_data_fit.sub_size)) phase_info.write("PSF shape = {} \n".format( self.meta_data_fit.psf_shape)) phase_info.write("Positions Threshold = {} \n".format( self.meta_data_fit.positions_threshold)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.write("Auto Link Priors = {} \n".format( self.auto_link_priors)) phase_info.close() def extend_with_multiple_hyper_phases( self, hyper_galaxy=False, inversion=False, include_background_sky=False, include_background_noise=False, ): hyper_phase_classes = [] if hyper_galaxy: if not include_background_sky and not include_background_noise: hyper_phase_classes.append( phase_extensions.hyper_galaxy_phase.HyperGalaxyPhase) elif include_background_sky and not include_background_noise: hyper_phase_classes.append(phase_extensions.hyper_galaxy_phase. HyperGalaxyBackgroundSkyPhase) elif not include_background_sky and include_background_noise: hyper_phase_classes.append(phase_extensions.hyper_galaxy_phase. HyperGalaxyBackgroundNoisePhase) else: hyper_phase_classes.append(phase_extensions.hyper_galaxy_phase. HyperGalaxyBackgroundBothPhase) if inversion: if not include_background_sky and not include_background_noise: hyper_phase_classes.append(phase_extensions.InversionPhase) elif include_background_sky and not include_background_noise: hyper_phase_classes.append( phase_extensions.InversionBackgroundSkyPhase) elif not include_background_sky and include_background_noise: hyper_phase_classes.append( phase_extensions.InversionBackgroundNoisePhase) else: hyper_phase_classes.append( phase_extensions.InversionBackgroundBothPhase) if len(hyper_phase_classes) == 0: return self else: return phase_extensions.CombinedHyperPhase( phase=self, hyper_phase_classes=hyper_phase_classes)
class PhaseDataset(abstract.AbstractPhase): gaussians = af.PhaseProperty("gaussians") Result = Result @af.convert_paths def __init__(self, paths, gaussians=None, optimizer_class=af.MultiNest): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_gaussians passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer """ super(PhaseDataset, self).__init__(paths, optimizer_class=optimizer_class) self.gaussians = gaussians or [] def run(self, dataset: Dataset, mask, results=None): """ Run this phase. Parameters ---------- mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed dataset: scaled_array.ScaledSquarePixelArray An masked_imaging that has been masked Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_gaussians. """ dataset.save(self.paths.phase_output_path) self.model = self.model.populate(results) analysis = self.make_analysis(dataset=dataset, mask=mask, results=results) self.customize_priors(results) self.assert_and_save_pickle() result = self.run_analysis(analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, results=None, mask=None): """ Create an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- mask: Mask The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ raise NotImplementedError()
class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, *, profiles, lens_redshift, source_redshift, regions=[], non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT): super().__init__(paths=paths, non_linear_class=non_linear_class) self.profiles = profiles if lens_redshift < source_redshift: self.lens_redshift = lens_redshift self.source_redshift = source_redshift else: raise ValueError( "The len's z={} must be lower than the source's z={}", format(lens_redshift, source_redshift)) self.transformer_class = transformer_class if not isinstance(regions, list): raise ValueError("""The variable "regions" must be a list.""") else: self.regions = regions @property def phase_folders(self): return self.optimizer.phase_folders def run(self, dataset: Dataset, xy_mask): analysis = self.make_analysis(dataset=dataset, xy_mask=xy_mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, xy_mask): masked_dataset = MaskedDataset(dataset=dataset, xy_mask=xy_mask) transformers = [] for i in range(masked_dataset.uv_wavelengths.shape[0]): transformers.append( self.transformer_class( uv_wavelengths=masked_dataset.uv_wavelengths[i], grid=masked_dataset.grid_3d.grid_2d.in_radians)) """ def get_continuum(masked_dataset, regions): pass continuum = np.zeros( shape=(dataset.visibilities.shape[0], ), dtype=bool ) for region in self.regions: continuum += region def func(masked_dataset, continuum): argspec = inspect.getargspec(MaskedDatasetLite.__init__) args = {} for argname in argspec.args: if argname not in ["self"]: if hasattr(masked_dataset, argname): array = getattr(masked_dataset, argname) args[argname] = reshape_array( array=array[~continuum] ) return MaskedDatasetLite(**args) masked_dataset_continuum = func(masked_dataset, continuum) #print(masked_dataset_continuum.uv_wavelengths.shape) transformer_continuum = self.transformer_class( uv_wavelengths=masked_dataset_continuum.uv_wavelengths, grid=masked_dataset.grid_3d.grid_2d.in_radians ) # dirty_image = transformer_continuum.image_from_visibilities( # visibilities=masked_dataset_continuum.visibilities # ) # plt.figure() # plt.imshow(dirty_image[::-1], cmap="jet") # plt.xticks([]) # plt.yticks([]) # plt.show() """ return Analysis(masked_dataset=masked_dataset, transformers=transformers, transformer_continuum=None, lens_redshift=self.lens_redshift, source_redshift=self.source_redshift, image_path=self.optimizer.paths.image_path) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class Phase(af.AbstractPhase): gaussian = af.PhaseProperty("gaussian") Result = Result @af.convert_paths def __init__(self, paths, gaussian, search): """ A phase which fits a Gaussian model using a non-linear search. Parameters ---------- paths : af.Paths Handles the output directory structure. gaussian : gaussians.Gaussian The model component Gaussian class fitted by this phase. search: class The class of a non_linear search """ super().__init__(paths=paths, search=search) self.gaussian = gaussian """ The run method is slightly different, as it now passed a mask in addition to the dataset. These are used to set up the masked-dataset in the 'analysis.py' module. """ def run(self, dataset: Dataset, mask): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. mask: Mask The mask used for the analysis. Returns ------- result: AbstractPhase.Result A result object comprising information on the non-linear search and the maximum likelihood model. """ analysis = self.make_analysis(dataset=dataset, mask=mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask): """ Create an Analysis object, which creates the dataset and contains the functions which perform the fit. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit log_likelihood for a given model instance. """ """To mask the dataset we simply pass both to the MaskedDataset class.""" masked_dataset = MaskedDataset(dataset=dataset, mask=mask) """ The 'image_path' is where visualizatiion of the model fit is output. Below, we direct it to the same path as the non-linear search output, but with an additional folder 'image' at the end. This path should be used for pretty much any project. """ return Analysis(masked_dataset=masked_dataset, image_path=self.search.paths.image_path) def make_result(self, result, analysis): return self.Result( samples=result.samples, previous_model=self.model, search=self.search, analysis=analysis, )
class PhaseImaging(dataset.PhaseDataset): galaxies = af.PhaseProperty("galaxies") hyper_image_sky = af.PhaseProperty("hyper_image_sky") hyper_background_noise = af.PhaseProperty("hyper_background_noise") Analysis = Analysis Result = Result @af.convert_paths def __init__( self, paths, *, galaxies=None, hyper_image_sky=None, hyper_background_noise=None, optimizer_class=af.MultiNest, cosmology=cosmo.Planck15, sub_size=2, signal_to_noise_limit=None, bin_up_factor=None, psf_shape_2d=None, positions_threshold=None, pixel_scale_interpolation_grid=None, inversion_uses_border=True, inversion_pixel_limit=None, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer sub_size: int The side length of the subgrid """ phase_tag = tagging.phase_tag_from_phase_settings( sub_size=sub_size, signal_to_noise_limit=signal_to_noise_limit, bin_up_factor=bin_up_factor, psf_shape_2d=psf_shape_2d, positions_threshold=positions_threshold, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, ) paths.phase_tag = phase_tag super().__init__( paths, galaxies=galaxies, optimizer_class=optimizer_class, cosmology=cosmology, ) self.hyper_image_sky = hyper_image_sky self.hyper_background_noise = hyper_background_noise self.is_hyper_phase = False self.meta_dataset = MetaImaging( model=self.model, bin_up_factor=bin_up_factor, psf_shape_2d=psf_shape_2d, sub_size=sub_size, signal_to_noise_limit=signal_to_noise_limit, positions_threshold=positions_threshold, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, inversion_uses_border=inversion_uses_border, inversion_pixel_limit=inversion_pixel_limit, ) # noinspection PyMethodMayBeStatic,PyUnusedLocal def modify_image(self, image, results): """ Customize an masked_imaging. e.g. removing lens light. Parameters ---------- image: scaled_array.ScaledSquarePixelArray An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result of the previous lens Returns ------- masked_imaging: scaled_array.ScaledSquarePixelArray The modified image (not changed by default) """ return image def make_analysis(self, dataset, mask, results=None, positions=None): """ Create an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ self.meta_dataset.model = self.model modified_image = self.modify_image(image=dataset.image, results=results) masked_imaging = self.meta_dataset.masked_dataset_from( dataset=dataset, mask=mask, positions=positions, results=results, modified_image=modified_image, ) self.output_phase_info() analysis = self.Analysis( masked_imaging=masked_imaging, cosmology=self.cosmology, image_path=self.optimizer.paths.image_path, results=results, ) return analysis def output_phase_info(self): file_phase_info = "{}/{}".format( self.optimizer.paths.phase_output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.optimizer).__name__)) phase_info.write("Sub-grid size = {} \n".format( self.meta_dataset.sub_size)) phase_info.write("PSF shape = {} \n".format( self.meta_dataset.psf_shape_2d)) phase_info.write("Positions Threshold = {} \n".format( self.meta_dataset.positions_threshold)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close()
class Phase(af.AbstractPhase): """ This tells the phase that the input parameter 'gaussian' is a model component that is fitted for by the phase's non-linear search. In 'analysis.py', the function 'fit' has an input parameter called 'instance' which is the gaussian mapped from this model via a unit vector and the model priors (as described in tutorial 1). For your model-fitting problem, this will be replaced by the modules in your 'model' package. """ gaussian = af.PhaseProperty("gaussian") Result = Result # Set the result to the Result class in 'result.py' @af.convert_paths # <- This handles setting up output paths. def __init__( self, paths, gaussian, # <- The user inputs a model -> gaussian.py -> Gaussian class here. search, # <- This specifies the default non-linear search used by the phase. ): """ A phase which fits a Gaussian model using a non-linear search. Parameters ---------- paths : af.Paths Handles the output directory structure. gaussian : model.gaussians.Gaussian The model component Gaussian class fitted by this phase. search: class The class of a non_linear search """ super().__init__(paths=paths, search=search) self.gaussian = gaussian def run(self, dataset: Dataset): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset : dataset.Dataset The dataset fitted by the phase, which is specified in the module 'dataset/dataset.py' Returns ------- result: result.Result A result object comprising information on the non-linear search and the maximum likelihood model. """ """ These functions create instances of the Analysis class (in 'analysis.py'), runs the analysis (which performs the non-linear search ) and returns an instance of the Result class (in 'result.py'). Once you've looked through this module, check those modules out to see exactly what these classes do! """ analysis = self.make_analysis(dataset=dataset) """ 'run_analysis' is not located in analysis.py, instead it is an inherited method from the parent class 'af.AbstractPhase'. Essentially, all this function does is begin the non-linear search, using the analysis created above. """ result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset): """ Create an Analysis object, which uses the dataset with functions to perform a fit. Parameters ---------- dataset : dataset.Dataset The dataset fitted by the phase, which is specified in the module 'dataset/dataset.py' Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit log_likelihood for a given model instance. """ return Analysis(dataset=dataset) def make_result(self, result, analysis): return self.Result( samples=result.samples, previous_model=self.model, search=self.search, analysis=analysis, )
class Phase(af.AbstractPhase): """ Because we now have multiple profiles in our model, we have renamed 'gaussian' to 'profiles'. As before, PyAutoFit uses this information to map the input Profile classes to a model instance when performing a fit. """ profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, settings, search): """ A phase which fits a model composed of multiple profiles (Gaussian, Exponential) using a non-linear search. Parameters ---------- paths : af.Paths Handles the output directory structure. profiles : [profiles.Profile] The model components (e.g. Gaussian, Exponenial) fitted by this phase. search: class The class of a non_linear search settings : PhaseSettings The collection of settings of the phase used to augment the data that is fitted and tag the output path. """ """ Here, we create a 'tag' for our phase. If we use an optional phase setting to alter the dataset we fit (here, a data_trim_ variable), we want to 'tag' the phase such that results are output to a unique directory whose names makes it explicit how the dataset was changed. If this setting is off, the tag is an empty string and thus the directory structure is not changed. """ paths.tag = settings.tag # The phase_tag must be manually added to the phase. super().__init__(paths=paths, search=search) self.profiles = profiles """ Phase settings alter the dataset that is fitted, however a phase does not have access to the dataset until it is run (e.g. the run method below is passed the dataset). In order for a phase to use its input phase settings to create the dataset it fits, these settings are stored in the 'meta_dataset' attribute and used when the 'run' and 'make_analysis' methods are called. """ self.meta_dataset = MetaDataset(settings=settings) def run(self, dataset: Dataset, mask): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. mask: Mask The mask used for the analysis. Returns ------- result: AbstractPhase.Result A result object comprising information on the non-linear search and the maximum likelihood model. """ analysis = self.make_analysis(dataset=dataset, mask=mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask): """ Create an Analysis object, which creates the dataset and contains the functions which perform the fit. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit log_likelihood for a given model instance. """ """ Here, the meta_dataset is used to create the masked dataset that is fitted. If the data_trim_left and / or data_trim_right settings are passed into the phase, the function below uses them to alter the masked dataset. Checkout 'meta_dataset.py' for more details. """ masked_dataset = self.meta_dataset.masked_dataset_from_dataset_and_mask( dataset=dataset, mask=mask) return Analysis(masked_dataset=masked_dataset, image_path=self.search.paths.image_path) def make_result(self, result, analysis): return self.Result( samples=result.samples, previous_model=self.model, search=self.search, analysis=analysis, )
class PhasePointSource(abstract.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Analysis = Analysis Result = Result def __init__( self, *, search, positions_solver, galaxies=None, settings=SettingsPhasePositions(), cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear search to try to fit models and hyper_galaxies passed to it. Parameters ---------- search: class The class of a non_linear search sub_size: int The side length of the subgrid """ super().__init__(search=search, settings=settings, galaxies=galaxies, cosmology=cosmology) self.positions_solver = positions_solver def make_analysis( self, positions, positions_noise_map, fluxes=None, fluxes_noise_map=None, imaging=None, results=None, ): """ Returns an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask2D The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the `NonLinearSearch` calls to determine the fit of a set of values """ self.output_phase_info() return self.Analysis( positions=positions, noise_map=positions_noise_map, fluxes=fluxes, fluxes_noise_map=fluxes_noise_map, solver=self.positions_solver, imaging=imaging, settings=self.settings, cosmology=self.cosmology, results=results, ) def run( self, positions, positions_noise_map, fluxes=None, fluxes_noise_map=None, imaging=None, results=None, info=None, pickle_files=None, ): """ Run this phase. Parameters ---------- mask: Mask2D The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed dataset: scaled_array.ScaledSquarePixelArray An masked_imaging that has been masked Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_galaxies. """ self.model = self.model.populate(results) results = results or af.ResultsCollection() analysis = self.make_analysis( positions=positions, positions_noise_map=positions_noise_map, fluxes=fluxes, fluxes_noise_map=fluxes_noise_map, imaging=imaging, results=results, ) result = self.run_analysis(analysis=analysis, info=info, pickle_files=pickle_files) return self.make_result(result=result, analysis=analysis) def output_phase_info(self): file_phase_info = path.join(self.search.paths.output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.search).__name__)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close()
class PhaseInterferometer(dataset.PhaseDataset): galaxies = af.PhaseProperty("galaxies") hyper_background_noise = af.PhaseProperty("hyper_background_noise") Analysis = Analysis Result = Result @af.convert_paths def __init__( self, paths, *, real_space_mask, galaxies=None, hyper_background_noise=None, optimizer_class=af.MultiNest, cosmology=cosmo.Planck15, sub_size=2, primary_beam_shape_2d=None, positions_threshold=None, pixel_scale_interpolation_grid=None, inversion_uses_border=True, inversion_pixel_limit=None, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer sub_size: int The side length of the subgrid """ paths.phase_tag = phase_tagging.phase_tag_from_phase_settings( sub_size=sub_size, real_space_shape_2d=real_space_mask.shape_2d, real_space_pixel_scales=real_space_mask.pixel_scales, primary_beam_shape_2d=primary_beam_shape_2d, positions_threshold=positions_threshold, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, ) super().__init__( paths, galaxies=galaxies, optimizer_class=optimizer_class, cosmology=cosmology, ) self.hyper_background_noise = hyper_background_noise self.is_hyper_phase = False self.meta_interferometer_fit = MetaInterferometerFit( model=self.model, sub_size=sub_size, real_space_mask=real_space_mask, primary_beam_shape_2d=primary_beam_shape_2d, positions_threshold=positions_threshold, pixel_scale_interpolation_grid=pixel_scale_interpolation_grid, inversion_uses_border=inversion_uses_border, inversion_pixel_limit=inversion_pixel_limit, ) # noinspection PyMethodMayBeStatic,PyUnusedLocal def modify_visibilities(self, visibilities, results): """ Customize an masked_interferometer. e.g. removing lens light. Parameters ---------- image: scaled_array.ScaledSquarePixelArray An masked_interferometer that has been masked results: autofit.tools.pipeline.ResultsCollection The result of the previous lens Returns ------- masked_interferometer: scaled_array.ScaledSquarePixelArray The modified image (not changed by default) """ return visibilities def make_analysis(self, dataset, mask, results=None, positions=None): """ Create an lens object. Also calls the prior passing and masked_interferometer modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline dataset: im.Interferometer An masked_interferometer that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ self.meta_interferometer_fit.model = self.model modified_visibilities = self.modify_visibilities( visibilities=dataset.visibilities, results=results ) masked_interferometer = self.meta_interferometer_fit.masked_dataset_from( dataset=dataset, mask=mask, positions=positions, results=results, modified_visibilities=modified_visibilities, ) self.output_phase_info() analysis = self.Analysis( masked_interferometer=masked_interferometer, cosmology=self.cosmology, image_path=self.optimizer.paths.image_path, results=results, ) return analysis def output_phase_info(self): file_phase_info = "{}/{}".format( self.optimizer.paths.phase_output_path, "phase.info" ) with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format(type(self.optimizer).__name__)) phase_info.write( "Sub-grid size = {} \n".format(self.meta_interferometer_fit.sub_size) ) phase_info.write( "Primary Beam shape = {} \n".format( self.meta_interferometer_fit.primary_beam_shape_2d ) ) phase_info.write( "Positions Threshold = {} \n".format( self.meta_interferometer_fit.positions_threshold ) ) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close() def extend_with_multiple_hyper_phases( self, hyper_galaxy=False, inversion=False, include_background_sky=False, include_background_noise=False, ): hyper_phase_classes = [] if hyper_galaxy: if not include_background_sky and not include_background_noise: hyper_phase_classes.append( extensions.hyper_galaxy_phase.HyperGalaxyPhase ) elif include_background_sky and not include_background_noise: hyper_phase_classes.append( extensions.hyper_galaxy_phase.HyperGalaxyBackgroundSkyPhase ) elif not include_background_sky and include_background_noise: hyper_phase_classes.append( extensions.hyper_galaxy_phase.HyperGalaxyBackgroundNoisePhase ) else: hyper_phase_classes.append( extensions.hyper_galaxy_phase.HyperGalaxyBackgroundBothPhase ) if inversion: if not include_background_sky and not include_background_noise: hyper_phase_classes.append(extensions.InversionPhase) elif include_background_sky and not include_background_noise: hyper_phase_classes.append(extensions.InversionBackgroundSkyPhase) elif not include_background_sky and include_background_noise: hyper_phase_classes.append(extensions.InversionBackgroundNoisePhase) else: hyper_phase_classes.append(extensions.InversionBackgroundBothPhase) if len(hyper_phase_classes) == 0: return self else: return extensions.CombinedHyperPhase( phase=self, hyper_phase_classes=hyper_phase_classes )
class PhaseImaging(dataset.PhaseDataset): galaxies = af.PhaseProperty("galaxies") hyper_image_sky = af.PhaseProperty("hyper_image_sky") hyper_background_noise = af.PhaseProperty("hyper_background_noise") Analysis = Analysis Result = Result @af.convert_paths def __init__( self, paths, *, search, galaxies=None, hyper_image_sky=None, hyper_background_noise=None, settings=SettingsPhaseImaging(), cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear search to try to fit models and hyper_galaxies passed to it. Parameters ---------- search: class The class of a non_linear search sub_size: int The side length of the subgrid """ super().__init__( paths, search=search, settings=settings, galaxies=galaxies, cosmology=cosmology, ) self.hyper_image_sky = hyper_image_sky self.hyper_background_noise = hyper_background_noise self.is_hyper_phase = False def make_phase_attributes(self, analysis): return PhaseAttributes( cosmology=self.cosmology, positions=analysis.masked_dataset.positions, hyper_model_image=analysis.hyper_model_image, hyper_galaxy_image_path_dict=analysis.hyper_galaxy_image_path_dict, ) def make_analysis(self, dataset, mask, results=None): """ Create an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear search calls to determine the fit of a set of values """ masked_imaging = imaging.MaskedImaging( imaging=dataset, mask=mask, settings=self.settings.settings_masked_imaging) self.output_phase_info() analysis = self.Analysis( masked_imaging=masked_imaging, settings=self.settings, cosmology=self.cosmology, image_path=self.search.paths.image_path, results=results, log_likelihood_cap=self.settings.log_likelihood_cap, ) return analysis def extend_with_stochastic_phase( self, stochastic_search=None, include_lens_light=False, include_pixelization=False, include_regularization=False, histogram_samples=500, histogram_bins=10, stochastic_method="gaussian", stochastic_sigma=0.0, ): if stochastic_search is None: stochastic_search = self.search.copy_with_name_extension( extension="") model_classes = [ag.mp.MassProfile] if include_lens_light: model_classes.append(ag.lp.LightProfile) if include_pixelization: model_classes.append(ag.pix.Pixelization) if include_regularization: model_classes.append(ag.reg.Regularization) return StochasticPhase( phase=self, search=stochastic_search, model_classes=tuple(model_classes), histogram_samples=histogram_samples, histogram_bins=histogram_bins, stochastic_method=stochastic_method, stochastic_sigma=stochastic_sigma, ) def output_phase_info(self): file_phase_info = "{}/{}".format(self.search.paths.output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.search).__name__)) phase_info.write("Sub-grid size = {} \n".format( self.settings.settings_masked_imaging.sub_size)) phase_info.write("PSF shape = {} \n".format( self.settings.settings_masked_imaging.psf_shape_2d)) phase_info.write("Positions Threshold = {} \n".format( self.settings.settings_lens.positions_threshold)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close()
class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, *, profiles, settings, search): """ A phase which fits a model composed of multiple profiles (Gaussian, Exponential) using a non-linear search. Parameters ---------- paths : af.Paths Handles the output directory structure. profiles : [profiles.Profile] The model components (e.g. Gaussian, Exponenial) fitted by this phase. search: class The class of a non_linear search data_trim_left : int or None The number of pixels by which the data is trimmed from the left-hand side. data_trim_right : int or None The number of pixels by which the data is trimmed from the right-hand side. """ paths.tag = settings.tag super().__init__(paths=paths, search=search) self.profiles = profiles self.meta_dataset = MetaDataset(settings=settings) @property def folders(self): return self.search.folders def run(self, dataset: Dataset, mask, info=None, results=None): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. mask: Mask The mask used for the analysis. Returns ------- result: AbstractPhase.Result A result object comprising information on the non-linear search and the maximum likelihood model. """ # These functions save the objects we will later access using the aggregator. They are saved via the 'pickle' # module in Python, which serializes the data on to the hard-disk. # See the 'dataset.py' module for a description of what the metadata is. self.save_metadata(dataset=dataset) self.save_dataset(dataset=dataset) self.save_mask(mask=mask) self.save_meta_dataset(meta_dataset=self.meta_dataset) self.model = self.model.populate(results) results = results or af.ResultsCollection() # This saves the search information of the phase, meaning that we can use the search instance # (e.g. Emcee) to interpret our results in the aggregator. analysis = self.make_analysis(dataset=dataset, mask=mask, results=results) result = self.run_analysis(analysis=analysis, info=info) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask, results=None): """ Create an Analysis object, which creates the dataset and contains the functions which perform the fit. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit log_likelihood for a given model instance. """ self.meta_dataset.model = self.model masked_dataset = self.meta_dataset.masked_dataset_from_dataset_and_mask( dataset=dataset, mask=mask ) return Analysis( masked_dataset=masked_dataset, image_path=self.search.paths.image_path ) def make_result(self, result, analysis): return self.Result(samples=result.samples, analysis=analysis)
class PhaseDataset(abstract.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Result = Result @af.convert_paths def __init__( self, paths, galaxies=None, optimizer_class=af.MultiNest, cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer """ super(PhaseDataset, self).__init__(paths, optimizer_class=optimizer_class) self.galaxies = galaxies or [] self.cosmology = cosmology self.is_hyper_phase = False def run(self, dataset: Dataset, mask, results=None, positions=None): """ Run this phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed dataset: scaled_array.ScaledSquarePixelArray An masked_imaging that has been masked Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_galaxies. """ dataset.save(self.paths.phase_output_path) self.save_metadata(dataset) self.model = self.model.populate(results) analysis = self.make_analysis(dataset=dataset, mask=mask, results=results, positions=positions) self.customize_priors(results) self.assert_and_save_pickle() result = self.run_analysis(analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask, results=None, positions=None): """ Create an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ raise NotImplementedError() def extend_with_inversion_phase(self): return extensions.InversionPhase(phase=self) def extend_with_multiple_hyper_phases( self, hyper_galaxy=False, inversion=False, include_background_sky=False, include_background_noise=False, hyper_galaxy_phase_first=False, ): self.use_as_hyper_dataset = True hyper_phase_classes = [] if self.meta_dataset.has_pixelization and inversion: if not include_background_sky and not include_background_noise: hyper_phase_classes.append(extensions.InversionPhase) elif include_background_sky and not include_background_noise: hyper_phase_classes.append( extensions.InversionBackgroundSkyPhase) elif not include_background_sky and include_background_noise: hyper_phase_classes.append( extensions.InversionBackgroundNoisePhase) else: hyper_phase_classes.append( extensions.InversionBackgroundBothPhase) if hyper_galaxy: if not include_background_sky and not include_background_noise: hyper_phase_classes.append( extensions.hyper_galaxy_phase.HyperGalaxyPhase) elif include_background_sky and not include_background_noise: hyper_phase_classes.append(extensions.hyper_galaxy_phase. HyperGalaxyBackgroundSkyPhase) elif not include_background_sky and include_background_noise: hyper_phase_classes.append(extensions.hyper_galaxy_phase. HyperGalaxyBackgroundNoisePhase) else: hyper_phase_classes.append(extensions.hyper_galaxy_phase. HyperGalaxyBackgroundBothPhase) if hyper_galaxy_phase_first: if inversion and hyper_galaxy: hyper_phase_classes = [ cls for cls in reversed(hyper_phase_classes) ] if len(hyper_phase_classes) == 0: return self else: return extensions.CombinedHyperPhase( phase=self, hyper_phase_classes=hyper_phase_classes)
class PhaseData(phase.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Result = Result Analysis = Analysis def __init__( self, phase_name, phase_tag, phase_folders=tuple(), galaxies=None, optimizer_class=af.MultiNest, cosmology=cosmo.Planck15, auto_link_priors=False, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer """ super(PhaseData, self).__init__( phase_name=phase_name, phase_tag=phase_tag, phase_folders=phase_folders, optimizer_class=optimizer_class, cosmology=cosmology, auto_link_priors=auto_link_priors, ) self.galaxies = galaxies or [] self.is_hyper_phase = False def run(self, data, results=None, mask=None, positions=None): """ Run this phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed data: scaled_array.ScaledSquarePixelArray An lens_data that has been masked Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_galaxies. """ self.variable = self.variable.populate(results) analysis = self.make_analysis(data=data, results=results, mask=mask, positions=positions) self.customize_priors(results) self.assert_and_save_pickle() result = self.run_analysis(analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, data, results=None, mask=None, positions=None): """ Create an lens object. Also calls the prior passing and lens_data modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask The default masks passed in by the pipeline data: im.Imaging An lens_data that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ raise NotImplementedError() def extend_with_inversion_phase(self): return phase_extensions.InversionPhase(phase=self)
class Phase(af.AbstractPhase): profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, lens_redshift, source_redshift, regions=None, non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT): super().__init__(paths=paths, non_linear_class=non_linear_class) self.profiles = profiles if lens_redshift < source_redshift: self.lens_redshift = lens_redshift self.source_redshift = source_redshift else: raise ValueError( "The len's z={} must be lower than the source's z={}", format(lens_redshift, source_redshift)) self.transformer_class = transformer_class if not isinstance(regions, list): raise ValueError("""The variable "regions" must be a list.""") else: self.regions = regions # TODO: Check if there is a clash between regions # self.continuum_idx = [] # for region in self.regions: # print(region) #exit() def run(self, dataset: Dataset, xy_mask, uv_mask=None): analysis = self.make_analysis(dataset=dataset, xy_mask=xy_mask, uv_mask=uv_mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, xy_mask, uv_mask): masked_dataset = MaskedDataset(dataset=dataset, xy_mask=xy_mask, uv_mask=uv_mask) transformers = [] for i in range(masked_dataset.uv_wavelengths.shape[0]): transformers.append( self.transformer_class( uv_wavelengths=masked_dataset.uv_wavelengths[i], grid=masked_dataset.grid_3d.grid_2d.in_radians)) return Analysis(masked_dataset=masked_dataset, transformers=transformers, lens_redshift=self.lens_redshift, source_redshift=self.source_redshift, image_path=self.optimizer.paths.image_path) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class Phase(af.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Result = Result @af.convert_paths def __init__( self, paths, *, galaxies, regions, non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT ): super().__init__(paths=paths, non_linear_class=non_linear_class) self.galaxies = galaxies if not isinstance(regions, list): raise ValueError( """The variable "regions" must be a list.""" ) else: self.regions = regions self.transformer_class = transformer_class @property def phase_folders(self): return self.optimizer.phase_folders def run(self, dataset: Dataset, xy_mask): analysis = self.make_analysis( dataset=dataset, xy_mask=xy_mask ) result = self.run_analysis(analysis=analysis) return self.make_result( result=result, analysis=analysis ) def make_analysis(self, dataset, xy_mask): # NOTE: The masked_dataset is no longer being used, instead each compoent # (i.e. continuum + emission line regions) each have their own masked_dataset # which is initialized here. def masked_datasets_from_regions(masked_dataset, regions): args = { "continuum":{} } idx = np.zeros( shape=(masked_dataset.visibilities.shape[0], ), dtype=bool ) for i, region in enumerate(regions): idx += region.idx args["region_{}".format(i)] = {} if all(idx): continuum = False else: continuum = True argspec = inspect.getargspec(MaskedDatasetLite.__init__) #args = {} for argname in argspec.args: if argname not in ["self"]: if hasattr(masked_dataset, argname): array = getattr(masked_dataset, argname) if continuum: args["continuum"][argname] = reshape_array( array=array[~idx] ) for i, region in enumerate(regions): args["region_{}".format(i)][argname] = reshape_array( array=array[region.idx] ) #args["region_{}".format(i)][argname] = np.average(a=array[region.idx], axis=0) masked_datasets = { "continuum":MaskedDatasetLite(**args["continuum"]) if continuum else None } for i, region in enumerate(regions): masked_datasets["region_{}".format(i)] = MaskedDatasetLite(**args["region_{}".format(i)]) return masked_datasets # NOTE: Multiple lines can be present in a cube, in which # case region will be a list (renamed to regions) - DONE # NOTE: Can we skip the initialization of the masked dataset? masked_dataset = MaskedDataset( dataset=dataset, xy_mask=xy_mask, ) masked_datasets = masked_datasets_from_regions( masked_dataset=masked_dataset, regions=self.regions ) transformers = {} for key in masked_datasets.keys(): if masked_datasets[key] is not None: transformers[key] = self.transformer_class( uv_wavelengths=masked_datasets[key].uv_wavelengths, grid=masked_dataset.grid_3d.grid_2d.in_radians ) else: transformers[key] = None return Analysis( masked_datasets=masked_datasets, transformers=transformers, grid=masked_dataset.grid_3d.grid_2d, image_path=self.optimizer.paths.image_path ) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )
class PhasePositions(abstract.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Analysis = Analysis Result = Result @af.convert_paths def __init__( self, paths, *, search, solver, galaxies=None, settings=SettingsPhasePositions(), cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear search to try to fit models and hyper_galaxies passed to it. Parameters ---------- search: class The class of a non_linear search sub_size: int The side length of the subgrid """ super().__init__( paths, search=search, settings=settings, galaxies=galaxies, cosmology=cosmology, ) self.solver = solver def make_attributes(self, analysis): return Attributes(cosmology=self.cosmology) def make_analysis(self, positions, imaging=None, results=None): """ Returns an lens object. Also calls the prior passing and masked_imaging modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask2D The default masks passed in by the pipeline dataset: im.Imaging An masked_imaging that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the `NonLinearSearch` calls to determine the fit of a set of values """ self.output_phase_info() analysis = self.Analysis( positions=positions, solver=self.solver, imaging=imaging, cosmology=self.cosmology, results=results, ) return analysis def output_phase_info(self): file_phase_info = path.join(self.search.paths.output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.search).__name__)) phase_info.write("Positions Threshold = {} \n".format( self.settings.positions_threshold)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close()
class PhaseGalaxy(af.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Analysis = Analysis def __init__( self, phase_name, phase_folders=tuple(), galaxies=None, use_image=False, use_convergence=False, use_potential=False, use_deflections=False, optimizer_class=af.MultiNest, sub_size=2, pixel_scale_interpolation_grid=None, mask_function=None, cosmology=cosmo.Planck15, ): """ A phase in an lens pipeline. Uses the set non_linear optimizer to try to fit models and hyper_galaxies passed to it. Parameters ---------- optimizer_class: class The class of a non_linear optimizer sub_size: int The side length of the subgrid """ super(PhaseGalaxy, self).__init__( phase_name=phase_name, phase_folders=phase_folders, optimizer_class=optimizer_class, ) self.cosmology = cosmology self.use_image = use_image self.use_convergence = use_convergence self.use_potential = use_potential self.use_deflections = use_deflections self.galaxies = galaxies self.sub_size = sub_size self.pixel_scale_interpolation_grid = pixel_scale_interpolation_grid self.mask_function = mask_function def run(self, galaxy_data, results=None, mask=None): """ Run this phase. Parameters ---------- galaxy_data mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection An object describing the results of the last phase or None if no phase has been executed Returns ------- result: AbstractPhase.Result A result object comprising the best fit model and other hyper_galaxies. """ analysis = self.make_analysis(galaxy_data=galaxy_data, results=results, mask=mask) self.variable = self.variable.populate(results) self.customize_priors(results) self.assert_and_save_pickle() result = self.run_analysis(analysis) return self.make_result(result, analysis) def make_analysis(self, galaxy_data, results=None, mask=None): """ Create an lens object. Also calls the prior passing and lens_data modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- galaxy_data mask: Mask The default masks passed in by the pipeline results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens: Analysis An lens object that the non-linear optimizer calls to determine the fit of a set of values """ mask = setup_phase_mask( data=galaxy_data[0], mask=mask, mask_function=self.mask_function, inner_mask_radii=None, ) if self.use_image or self.use_convergence or self.use_potential: galaxy_data = gd.GalaxyFitData( galaxy_data=galaxy_data[0], mask=mask, pixel_scale_interpolation_grid=self. pixel_scale_interpolation_grid, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=self.use_deflections, use_deflections_x=self.use_deflections, ) return AnalysisSingle( galaxy_data=galaxy_data, cosmology=self.cosmology, image_path=self.optimizer.image_path, results=results, ) elif self.use_deflections: galaxy_data_y = gd.GalaxyFitData( galaxy_data=galaxy_data[0], mask=mask, pixel_scale_interpolation_grid=self. pixel_scale_interpolation_grid, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=self.use_deflections, use_deflections_x=False, ) galaxy_data_x = gd.GalaxyFitData( galaxy_data=galaxy_data[1], mask=mask, pixel_scale_interpolation_grid=self. pixel_scale_interpolation_grid, use_image=self.use_image, use_convergence=self.use_convergence, use_potential=self.use_potential, use_deflections_y=False, use_deflections_x=self.use_deflections, ) return AnalysisDeflections( galaxy_data_y=galaxy_data_y, galaxy_data_x=galaxy_data_x, cosmology=self.cosmology, image_path=self.optimizer.image_path, results=results, )
class Phase(af.AbstractPhase): """ Because we now have multiple profiles in our model, we have renamed 'gaussian' to 'profiles'. As before, PyAutoFit uses this information to map the input Profile classes to a model instance when performing a fit. Whereas the 'gaussian' variable took a single Gaussian object in the previous tutorials, the 'profiles' variable is a list of model component objects. The PhaseProperty class below accounts for this, such that the instance object passed into the log likelihood function can be iterated over like a list. """ profiles = af.PhaseProperty("profiles") Result = Result @af.convert_paths def __init__(self, paths, profiles, search): """ A phase which fits a model composed of multiple profiles (Gaussian, Exponential) using a non-linear search. Parameters ---------- paths : af.Paths Handles the output directory structure. profiles : [profiles.Profile] The model components (e.g. Gaussian, Exponenial) fitted by this phase. search: class The class of a non_linear search """ super().__init__(paths=paths, search=search) self.profiles = profiles def run(self, dataset: Dataset, mask): """ Pass a dataset to the phase, running the phase and non-linear search. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. mask: Mask The mask used for the analysis. Returns ------- result: AbstractPhase.Result A result object comprising information on the non-linear search and the maximum likelihood model. """ analysis = self.make_analysis(dataset=dataset, mask=mask) result = self.run_analysis(analysis=analysis) return self.make_result(result=result, analysis=analysis) def make_analysis(self, dataset, mask): """ Create an Analysis object, which creates the dataset and contains the functions which perform the fit. Parameters ---------- dataset: aa.Dataset The dataset fitted by the phase, as defined in the 'dataset.py' module. Returns ------- analysis : Analysis An analysis object that the non-linear search calls to determine the fit log_likelihood for a given model instance. """ masked_dataset = MaskedDataset(dataset=dataset, mask=mask) return Analysis(masked_dataset=masked_dataset, image_path=self.search.paths.image_path) def make_result(self, result, analysis): return self.Result( samples=result.samples, previous_model=self.model, search=self.search, analysis=analysis, )
class PhaseInterferometer(dataset.PhaseDataset): galaxies = af.PhaseProperty("galaxies") hyper_background_noise = af.PhaseProperty("hyper_background_noise") Analysis = Analysis Result = Result def __init__( self, *, search, real_space_mask, galaxies=None, hyper_background_noise=None, settings=SettingsPhaseInterferometer(), cosmology=cosmo.Planck15, use_as_hyper_dataset=False, ): """ A phase in an lens pipeline. Uses the set non_linear search to try to fit models and hyper_galaxies passed to it. Parameters ---------- search: class The class of a non_linear search sub_size: int The side length of the subgrid """ search.paths.tag = settings.phase_tag_with_inversion super().__init__( search=search, galaxies=galaxies, settings=settings, cosmology=cosmology, use_as_hyper_dataset=use_as_hyper_dataset, ) self.hyper_background_noise = hyper_background_noise self.is_hyper_phase = False self.real_space_mask = real_space_mask def make_analysis(self, dataset, mask, results=None): """ Returns an lens object. Also calls the prior passing and masked_interferometer modifying functions to allow child classes to change the behaviour of the phase. Parameters ---------- positions mask: Mask2D The default masks passed in by the pipeline dataset: im.Interferometer An masked_interferometer that has been masked results: autofit.tools.pipeline.ResultsCollection The result from the previous phase Returns ------- lens : Analysis An lens object that the `NonLinearSearch` calls to determine the fit of a set of values """ masked_interferometer = interferometer.MaskedInterferometer( interferometer=dataset, visibilities_mask=mask, real_space_mask=self.real_space_mask, settings=self.settings.settings_masked_interferometer, ) self.output_phase_info() return self.Analysis( masked_interferometer=masked_interferometer, settings=self.settings, cosmology=self.cosmology, results=results, ) def output_phase_info(self): file_phase_info = path.join(self.search.paths.output_path, "phase.info") with open(file_phase_info, "w") as phase_info: phase_info.write("Optimizer = {} \n".format( type(self.search).__name__)) phase_info.write("Sub-grid size = {} \n".format( self.settings.settings_masked_interferometer.sub_size)) phase_info.write("Positions Threshold = {} \n".format( self.settings.settings_lens.positions_threshold)) phase_info.write("Cosmology = {} \n".format(self.cosmology)) phase_info.close()
class Phase(af.AbstractPhase): galaxies = af.PhaseProperty("galaxies") Result = Result @af.convert_paths def __init__( self, paths, *, galaxies, region, non_linear_class=af.MultiNest, transformer_class=al.TransformerFINUFFT ): super().__init__(paths=paths, non_linear_class=non_linear_class) self.galaxies = galaxies self.region = region self.transformer_class = transformer_class def run(self, dataset: Dataset, xy_mask): analysis = self.make_analysis( dataset=dataset, xy_mask=xy_mask ) result = self.run_analysis(analysis=analysis) return self.make_result( result=result, analysis=analysis ) def make_analysis(self, dataset, xy_mask): # NOTE: Multiple lines can be present in a cube, in which # case region will be a list (renamed to regions) masked_dataset = MaskedDataset( dataset=dataset, xy_mask=xy_mask, region=self.region ) masked_dataset_continuum = RegionMaskedDataset( dataset=masked_dataset.dataset_outside_region, uv_mask=masked_dataset.uv_mask_outside_region, continuum=True ) masked_dataset_line = RegionMaskedDataset( dataset=masked_dataset.dataset_inside_region, uv_mask=masked_dataset.uv_mask_inside_region, continuum=False ) transformers = [] for i in range(masked_dataset.uv_wavelengths.shape[0]): transformers.append( self.transformer_class( uv_wavelengths=masked_dataset.uv_wavelengths[i], grid=masked_dataset.grid_3d.grid_2d.in_radians ) ) transformer_continuum = self.transformer_class( uv_wavelengths=masked_dataset_continuum.uv_wavelengths, grid=masked_dataset.grid_3d.grid_2d.in_radians ) # # NOTE: EXPERIMENTAL # holder = RegionMaskedDatasetsHolder( # region_masked_datasets=[ # masked_dataset_continuum, # masked_dataset_line # ] # ) # exit() # TODO: region_masked_datasets can be a class that holds individual # masked datasets and it's only function will be to differentiate between # a masked_dataset corresponding to the continuum and the rest. return Analysis( masked_dataset=masked_dataset, region_masked_datasets=[ masked_dataset_continuum, masked_dataset_line ], transformers=transformers, transformer_continuum=transformer_continuum, image_path=self.optimizer.paths.image_path ) def make_result(self, result, analysis): return self.Result( instance=result.instance, likelihood=result.likelihood, analysis=analysis, output=result.output, )