Point Sources#
So far, we have shown strongly lensed galaxies whose extended surface brightness is lensed into the awe-inspiring giant arcs and Einstein rings we see in high quality telescope imaging. There are many lenses where the background source is not extended but is instead a point-source, for example strongly lensed quasars and supernovae.
For these objects, we do not want to model the source using a LightProfile
which implicitly assumes an extended
surface brightness distribution. Instead, we assume that our source is a point source with a centre (y,x). Our
ray-tracing calculations no longer trace extended light rays from the source plane to the image-plane, but instead
now find the locations the point-source’s multiple images appear in the image-plane.
Here is an example of a compact source that has been simulated in PyAutoLens, with the positions of its four multiple images marked using stars:

Point Sources#
For point source modeling, our goal is to find the multiple images of a lens mass model given a (y,x) coordinate in the
source plane. This is an iterative problem performed in a very different way to ray-tracing used when evaluating a
LightProfile
.
To treat a source as a point source, we create it as a galaxy using Point
object and pass it to a tracer:
lens_galaxy = al.Galaxy(
redshift=0.5,
mass=al.mp.Isothermal(
centre=(0.001, 0.001), einstein_radius=1.0, ell_comps=(0.0, 0.111111)
)
)
point_source = al.ps.Point(centre=(0.07, 0.07))
source_galaxy = al.Galaxy(redshift=1.0, point_0=point_source)
tracer = al.Tracer.from_galaxies(galaxies=[lens_galaxy, source_galaxy])
Position Solving#
This tracer allows us to compute deflection angles and therefore map image-pixels to the source-plane. We can therefore
pass it to the PositionSolver
object to solve for the image-pixel coordinates which correspond to the source’s
source-plane position at (0.07”, 0.07”).
There are many options that can be passed to a PositionsSovler
, below we only specify the precision we want the
image-plane coordinates to be calculated too, which is 0.001”, much lower than the resolution fo the data we observed
the point-sources on!
solver = al.PointSolver(
grid=grid_2d,
pixel_scale_precision=0.001,
)
positions = solver.solve(lensing_obj=tracer, source_plane_coordinate=(0.07, 0.07))
Here is what the solved positions look like, compared to the observe data. In this example, the data was simulated with the mass-model we used above, so the match is good:
[Missing]
Point Source Dataset#
PyAutoLens has full support for analysing strong lens datasetsas a point-source. This might be used for analysing strongly lensed quasars or supernovae, which are so compact we do not observe their extended emission.
To perform point-source analysing, we first create a PointDataset
containing the image-plane (y,x) positions
of each multiple image and their noise values (which would be the resolution of the imaging data they are observed).
The positions below correspond to those of an Isothermal
mass model.
point_dataset = al.PointDataset(
name="point_0",
positions=al.Grid2DIrregular(
[[1.1488, -1.1488], [1.109, 1.109], [-1.109, -1.109], [-1.1488, 1.1488]]
),
positions_noise_map=al.ArrayIrregular([0.05, 0.05, 0.05, 0.05]),
)
In this simple example we model a single point source, which might correspond to one lensed quasar or supernovae. However, PyAutoLens supports model-fits to datasets with many lensed point-sources, which is used for analysing group-scale and cluster-scale strong lenses.
Each point source dataset is therefore passed into a PointDict
object before the model-fit is performed. For
this simple example only one dataset is passed in, but in the galaxy-cluster examples you’ll see this object makes it
straightforward to model datasets with many lensed sources.
point_dict = al.PointDict(point_dataset_list=[point_dataset])
We can print the positions
of this dictionary and dataset, as well as their noise-map values.
print("Point Source Dataset Name:")
print(point_dict["point_0"].name)
print("Point Source Multiple Image (y,x) Arc-second Coordinates:")
print(point_dict["point_0"].positions.in_list)
print("Point Source Multiple Image Noise-map Values:")
print(point_dict["point_0"].positions_noise_map.in_list)
Name Pairing#
Every point-source dataset in the PointDict
has a name, which in this example was point_0
. This name
pairs the dataset to the Point
in the model below. Because the name of the dataset is point_0
, the
only Point
object that is used to fit it must have the name point_0
.
This ensures if a dataset has many point sources (e.g. galaxy clusters) it is clear how the model pairs the data.
Fitting#
Just like we used a Tracer
to fit imaging and interferometer data, we can use it to
fit point-source data via the FitPoint
object.
This uses the names of each point-source in the dataset and model to create individual fits to the positions
,
fluxes
and other attributes that could be fitted. This allows us to inspect the residual-map,
chi-squared, likelihood, etc of every individual fit to part of our point source dataset.
fit = al.FitPointDict(point_dict=point_dict, tracer=tracer, point_solver=solver)
print(fit["point_0"].positions.residual_map)
print(fit["point_0"].positions.chi_squared_map)
print(fit["point_0"].positions.log_likelihood)
Lens Modeling#
It is straight forward to fit a lens model to a point source dataset, using the same API that we saw for imaging and interferometer datasets.
This uses an AnalysisPoint
object which fits the lens model in the correct way for a point source dataset.
This includes mapping the name
’s of each dataset in the PointDict
to the names of the point sources in
the lens model.
# Lens:
bulge = af.Model(al.lp.Sersic)
mass = af.Model(al.mp.Isothermal)
lens = af.Model(
al.Galaxy, redshift=0.5, bulge=bulge, mass=mass
)
# Source:
point_0 = af.Model(al.ps.Point)
source = af.Model(al.Galaxy, redshift=1.0, point_0=point_0)
# Overall Lens Model:
galaxies = af.Collection(lens=lens, source=source)
model = af.Collection(galaxies=galaxies)
# Search + Analysis + Model-Fit
search = af.DynestyStatic(name="overview_point_source")
analysis = al.AnalysisPoint(point_dict=point_dict, solver=solver)
result = search.fit(model=model, analysis=analysis)
Wrap-Up#
The point_source package of the autolens_workspace contains numerous example scripts for performing point source modeling to datasets where there are only a couple of lenses and lensed sources, which fall under the category of ‘galaxy scale’ objects.
This also includes examples of how to add and fit other information that are observed by a point-source source, for example the flux of each image.