# 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.EllIsothermal(
)
)

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 `EllIsothermal` 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.ValuesIrregular([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_galaxy_model = af.Model(al.Galaxy, redshift=0.5, mass=al.mp.EllIsothermal)
source_galaxy_model = af.Model(al.Galaxy, redshift=1.0, point_0=al.ps.Point)

galaxies = af.Collection(lens=lens_galaxy_model, source=source_galaxy_model)
model = af.Collection(galaxies=galaxies)

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.