This demo will demonstrate the basics of cluster lenses as of CosmoSim v3.1. We follow the pattern from CosmoSim Demo I and Sample Datasets, and we will not take up space to explain constructs known therefrom.
Preparation¶
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import json
from CosmoSim.datagen import SimImage
import CosmoSim.Image as csimg
import CosmoSim.dataset as csd
from CosmoSim import ParametersFirst test of Cluster Lenses¶
We choose the following parameters for the first simulation.
cfg = { "simulator" : { "model" : "Raytrace", "cropsize" : 256 }
, 'lens': { "cluster" : "SIE/5/5/8/0.3/45;SIE/-5/-5/8/0.3/45" }
, 'source': {
'mode': 'Spherical',
'sigma': 5,
'theta': 45,
'position': 'cartesian'}
, 'position': { 'x': 11.01, 'y': 0.31 }
}
param = Parameters( cfg )The new element is the lens specification, which is not as user friendly as it was.
The cluster attribute gives a list of lenses separated by semicolon.
Each constituent lens consists of the lens model ("SIE") and a list of
lens parameters separated by slash (/). For SIE, these parameters are
////, i.e. position , Einstein radius,
ellipticity, and orientation.
Given the parameters, the simulation is as before.
imsim = SimImage( param, verbose=0 )
im = imsim.getImage()
csimg.imshow( im, title="First example of a cluster lens" )
Random dataset¶
We can also generate random datasets.
cfg = csd.readtoml( "cluster.toml" )
display( json.dumps( cfg ) )'{"simulator": {"model": "Raytrace", "size": 18000, "nterms": 4, "imagesize": 512, "cropsize": 256, "centred": true}, "lens": {"mode": "SIE", "einstein-min": 20, "einstein-max": 75, "orientation-min": 0, "orientation-max": 180, "ellipseratio-min": 0.1, "ellipseratio-max": 0.9}, "cluster": {"count": 2, "maxrelativelocation": 1.2}, "source": {"mode": "SersicSphere", "n_sersic-min": 1, "n_sersic-max": 5, "luminosity-min": 10, "luminosity-max": 20, "luminosity-lambda": 2.0, "sigma-min": 1, "sigma-max": 4, "position": "relative"}, "position": {"phi-min": 0, "phi-max": 360, "r-relativemax": 0.4}}'Each constituent lens is placed in a random direction from the origin,
at a random distance upper bounded as where is
the Einstein radius and is the constant given as cluster.maxrelativelocation.
We can draw a random object as before.
ob = csd.getline( cfg, fn="test.png" )
display( ob )index 0
filename test.png
model Raytrace
cluster SIE/-6.605119422431851/-21.363376547311095/47....
source SersicSphere
R 78.333585
phi 98.566468
sigma 3.772596
sigma2 16.194565
theta 19.394465
n_sersic 2.803967
luminosity 17.139406
x -11.668308
y 77.459675
dtype: objectparam = Parameters( )
param.setRow( ob )
imsim = SimImage( param, verbose=2 )
im = imsim.getImage()
csimg.imshow( im )[GenericSim] init (verbose=2) ...
[SimImage] init (verbose=2) ...
[getSource] src=SersicSphere, ltprf0=None, verbose=2
[getSource] Lightprofile: SersicSphere LightProfileSpec.Sersic
[getSource] mode=SourceSpec.Sphere, ltprf=LightProfileSpec.Sersic
[getSource] Spherical Source - n_sersic=2.8039673447516504, luminosity=17.13940622883135
[SphericalSource] constructor done
getSource() returns
[CosmoSim/py] setCluster(SIE/-6.605119422431851/-21.363376547311095/47.81520262902683/0.6441970301075443/79.37281805353093;SIE/-18.340655772254845/8.614008728989585/21.361129792720348/0.39068158331413194/100.69668496016078)
SIE : [-6.605119422431851, -21.363376547311095, 47.81520262902683, 0.6441970301075443, 79.37281805353093]
[ClusterLens] component lens instantiated
[ClusterLens] [-6.605119422431851, -21.363376547311095, 47.81520262902683, 0.6441970301075443, 79.37281805353093]
[ClusterLens] addLens (-6.605119422431851, -21.363376547311095) <CosmoSim.CosmoSimPy.SIE object at 0x7f96d5a042b0>
[ClusterLens] addLens done
[ClusterLens] Done one component lens
SIE : [-18.340655772254845, 8.614008728989585, 21.361129792720348, 0.39068158331413194, 100.69668496016078]
[ClusterLens] component lens instantiated
[ClusterLens] [-18.340655772254845, 8.614008728989585, 21.361129792720348, 0.39068158331413194, 100.69668496016078]
[ClusterLens] addLens (-18.340655772254845, 8.614008728989585) <CosmoSim.CosmoSimPy.SIE object at 0x7f96d6bb67f0>
[ClusterLens] addLens done
[ClusterLens] Done one component lens
[CosmoSim/py] setCluster calls setLens
[initSim] XY -11.668308253189284 77.45967458792074
ClusterLens::addLens]] 5
ClusterLens::addLens]] -5
[ClusterLens.initAlphasBetas] nosuchfile
[Source] Constructor
[SphericalSource] SERSIC
setFile /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
ClusterLens::addLens]] -21.3634
setFile /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
ClusterLens::addLens]] 8.61401
[ClusterLens.initAlphasBetas] nosuchfile
[PsiFunctionLens.initAlphasBetas] Amplitudes file /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
[initAlphasBetas] opened file /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
[PsiFunctionLens.initAlphasBetas] Amplitudes file /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
[initAlphasBetas] opened file /home/runner/.local/lib/python3.14/site-packages/CosmoSim/sie05.txt
[SimulatorMode::setLens] ClusterLens [SIE;SIE;]
[SimulatorModel::setSource] setting source
[SimulatorModel::setNterms] 10 -> 5
[SimulatorModel::update] Lens: ClusterLens [SIE;SIE;]
[Lens::getXi] [-11.6683, 77.4597]
[Lens] Fix pt it'n 0; xi0=[-11.6683, 77.4597]; Delta eta = -0.24276, 73.1741
[Lens] Fix pt it'n 1; xi0=[-11.9111, 150.634]; Delta eta = -0.154467, 73.2567
[Lens] Fix pt it'n 2; xi0=[-11.8228, 150.716]; Delta eta = -0.125855, 73.257
[Lens] Fix pt it'n 3; xi0=[-11.7942, 150.717]; Delta eta = -0.116652, 73.257
[Lens] Good approximation: xi0=[-11.7942, 150.717]; xi1=[-11.785, 150.717]
[Lens::getXi] [-11.6683, 77.4597] -> [-11.785, 150.717]
[setNu] etaOffset set to zero.
[SimulatorModel::update] Done updateApparentAbs()
[SimulatorModel::update] thread section
[Source::getImage()]
[SimulatorModel::updateInner()] eta=[-11.6683, 77.4597]
[SimulatorModel::updateInner()] xi=[-11.785, 150.717]; eta=[-11.6683, 77.4597]; etaOffset=[0, 0]
[SimulatorModel::updateInner()] nu=[-11.785, 150.717]
[calculateAlphaBeta] [[-11.785, 150.717]] ...
[ClusterLens->calculateAlphaBeta()] 5; [-11.785, 150.717]
[PsiFunctionLens.calculateAlphaBeta()] 5; 47.8152 - [-11.785, 150.717]
ClusterLens (0, 0) 0/0
ClusterLens (0, 1) 0/0
ClusterLens (1, 0) -0.129525/0
ClusterLens (1, 1) 0/0
ClusterLens (1, 2) -0.127951/-0.0201328
ClusterLens (2, 0) 0/0
ClusterLens (2, 1) 9.61047e-05/0.00129661
ClusterLens (2, 2) 0/0
ClusterLens (2, 3) -0.000234281/0.00126534
ClusterLens (3, 0) -6.78788e-06/0
ClusterLens (3, 1) 0/0
ClusterLens (3, 2) 1.39934e-05/-1.3139e-06
ClusterLens (3, 3) 0/0
ClusterLens (3, 4) 1.99542e-05/4.61424e-06
ClusterLens (4, 0) 0/0
ClusterLens (4, 1) -2.5366e-09/2.24988e-07
ClusterLens (4, 2) 0/0
ClusterLens (4, 3) -2.4172e-08/-2.37668e-07
ClusterLens (4, 4) 0/0
ClusterLens (4, 5) 1.24769e-07/-4.35342e-07
ClusterLens (5, 0) -2.38708e-09/0
ClusterLens (5, 1) 0/0
ClusterLens (5, 2) 5.35736e-09/2.39911e-10
ClusterLens (5, 3) 0/0
ClusterLens (5, 4) -5.48105e-09/6.04774e-10
ClusterLens (5, 5) 0/0
ClusterLens (5, 6) -1.21444e-08/-4.23159e-09
[PsiFunctionLens.calculateAlphaBeta()] 5; 21.3611 - [-11.785, 150.717]
ClusterLens (0, 0) 0/0
ClusterLens (0, 1) 0/0
ClusterLens (1, 0) -0.173906/0
ClusterLens (1, 1) 0/0
ClusterLens (1, 2) -0.171793/-0.0270312
ClusterLens (2, 0) 0/0
ClusterLens (2, 1) 2.12692e-05/0.00173246
ClusterLens (2, 2) 0/0
ClusterLens (2, 3) -0.000349604/0.00169054
ClusterLens (3, 0) -9.49873e-06/0
ClusterLens (3, 1) 0/0
ClusterLens (3, 2) 1.79847e-05/3.96428e-08
ClusterLens (3, 3) 0/0
ClusterLens (3, 4) 2.63765e-05/7.06315e-06
ClusterLens (4, 0) 0/0
ClusterLens (4, 1) -1.63935e-08/3.13837e-07
ClusterLens (4, 2) 0/0
ClusterLens (4, 3) 3.26962e-09/-2.90946e-07
ClusterLens (4, 4) 0/0
ClusterLens (4, 5) 1.90231e-07/-5.68284e-07
ClusterLens (5, 0) -3.49144e-09/0
ClusterLens (5, 1) 0/0
ClusterLens (5, 2) 7.19361e-09/8.05601e-10
ClusterLens (5, 3) 0/0
ClusterLens (5, 4) -6.40921e-09/-5.80483e-11
ClusterLens (5, 5) 0/0
ClusterLens (5, 6) -1.56519e-08/-6.36577e-09
[RaytraceModel] distort() ClusterLens [SIE;SIE;] (Spherical Source)
[RaytraceModel] distort() ClusterLens [SIE;SIE;] (Spherical Source)
[RaytraceModel] distort() ClusterLens [SIE;SIE;] (Spherical Source)
[RaytraceModel] distort() ClusterLens [SIE;SIE;] (Spherical Source)
Time to update(): 65 milliseconds
[Simulator] Centre Point (-11.02,149.89) (Centre of Luminence in Planar Co-ordinates)
[getImage] centring from parameters: None

A sample¶
def mkimg(ob):
p0 = Parameters( )
p0.setRow( ob )
sim = SimImage( p0, verbose=0 )
return sim.getImage()obs = [ csd.getline( cfg ) for _ in range(8) ]
ims = [ mkimg(ob) for ob in obs ]
ts = [ f"Image {i}" for i in range(8) ]
csimg.showImages( ims, size=(2,4), titles=ts )[SimulatorModel::getDistorted()]
[Source] Destructor - destructed
[setDebug] 0

If we take a particular interest in one particular image, say no 1, we can easily inspect its parameters.
print( obs[1] )index 0
filename image-000000.png
model Raytrace
cluster SIE/12.455182623584644/-5.64548249790221/56.15...
source SersicSphere
R 61.541993
phi 326.788425
sigma 1.413445
sigma2 18.022888
theta 78.3291
n_sersic 3.473641
luminosity 11.264397
x 51.489335
y -33.708535
dtype: object
The cluser specification does not show in the row view, but we can single that one out to see properly.
print( obs[1]["cluster"] )SIE/12.455182623584644/-5.64548249790221/56.15451175475593/0.23186423939783368/85.72910801708368;SIE/4.3546181826464085/-1.3535007479736356/41.88317559875979/0.6362615269818876/30.403443230426795