diff --git a/dataset/cluster/test/data.fits b/dataset/cluster/test/data.fits index 14171106..08986bb4 100644 Binary files a/dataset/cluster/test/data.fits and b/dataset/cluster/test/data.fits differ diff --git a/dataset/cluster/test/mass.csv b/dataset/cluster/test/mass.csv index 21d32bf7..6d2cc9c3 100644 --- a/dataset/cluster/test/mass.csv +++ b/dataset/cluster/test/mass.csv @@ -1,5 +1,5 @@ -galaxy,attr_name,profile_class,y,x,ra,rs,b0,mass_at_200,redshift_object,redshift_source,redshift -lens_0,mass,dPIEMassSph,0.0,0.0,8.0,20.0,3.0,,,,0.5 -lens_1,mass,dPIEMassSph,10.0,8.0,5.0,12.0,1.2,,,,0.5 -extra_0,mass,dPIEMassSph,-7.0,-4.0,2.0,8.0,0.5,,,,0.5 -host_halo,dark,NFWMCRLudlowSph,0.0,0.0,,,,1995262314968882.8,0.5,2.0,0.5 +galaxy,attr_name,profile_class,y,x,sigma,r_core,r_cut,redshift_object,redshift_source,H0,Om0,mass_at_200,redshift +lens_0,mass,dPIEMassSph,0.0,0.0,330.0,8.0,20.0,0.5,2.0,67.66,0.30966,,0.5 +lens_1,mass,dPIEMassSph,10.0,8.0,210.0,5.0,12.0,0.5,2.0,67.66,0.30966,,0.5 +extra_0,mass,dPIEMassSph,-7.0,-4.0,135.0,2.0,8.0,0.5,2.0,67.66,0.30966,,0.5 +host_halo,dark,NFWMCRLudlowSph,0.0,0.0,,,,0.5,2.0,,,1995262314968882.8,0.5 diff --git a/dataset/cluster/test/noise_map.fits b/dataset/cluster/test/noise_map.fits index b671cfca..e703ebc5 100644 Binary files a/dataset/cluster/test/noise_map.fits and b/dataset/cluster/test/noise_map.fits differ diff --git a/dataset/cluster/test/point_dataset_0.json b/dataset/cluster/test/point_dataset_0.json index 0f548435..cfea1997 100644 --- a/dataset/cluster/test/point_dataset_0.json +++ b/dataset/cluster/test/point_dataset_0.json @@ -2,45 +2,50 @@ "type": "instance", "class_path": "autolens.point.dataset.PointDataset", "arguments": { - "time_delays_noise_map": null, + "time_delays": null, + "fluxes": null, "name": "point_0", - "positions": { + "positions_noise_map": { "type": "instance", - "class_path": "autoarray.structures.grids.irregular_2d.Grid2DIrregular", + "class_path": "autoarray.structures.arrays.irregular.ArrayIrregular", "arguments": { "values": { "type": "ndarray", "array": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] + 0.005, + 0.005, + 0.005 ], "dtype": "float64" } } }, - "positions_noise_map": { + "positions": { "type": "instance", - "class_path": "autoarray.structures.arrays.irregular.ArrayIrregular", + "class_path": "autoarray.structures.grids.irregular_2d.Grid2DIrregular", "arguments": { "values": { "type": "ndarray", "array": [ - 0.005, - 0.005 + [ + -11.165625, + -18.56902803281134 + ], + [ + -0.0390625, + -0.12358904199840427 + ], + [ + 3.00859375, + 23.4498930819527 + ] ], "dtype": "float64" } } }, - "fluxes": null, + "redshift": 1.0, "fluxes_noise_map": null, - "time_delays": null, - "redshift": 1.0 + "time_delays_noise_map": null } } \ No newline at end of file diff --git a/dataset/cluster/test/point_dataset_1.json b/dataset/cluster/test/point_dataset_1.json index 2c9e1efb..cb442f40 100644 --- a/dataset/cluster/test/point_dataset_1.json +++ b/dataset/cluster/test/point_dataset_1.json @@ -2,45 +2,50 @@ "type": "instance", "class_path": "autolens.point.dataset.PointDataset", "arguments": { - "time_delays_noise_map": null, + "time_delays": null, + "fluxes": null, "name": "point_1", - "positions": { + "positions_noise_map": { "type": "instance", - "class_path": "autoarray.structures.grids.irregular_2d.Grid2DIrregular", + "class_path": "autoarray.structures.arrays.irregular.ArrayIrregular", "arguments": { "values": { "type": "ndarray", "array": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] + 0.005, + 0.005, + 0.005 ], "dtype": "float64" } } }, - "positions_noise_map": { + "positions": { "type": "instance", - "class_path": "autoarray.structures.arrays.irregular.ArrayIrregular", + "class_path": "autoarray.structures.grids.irregular_2d.Grid2DIrregular", "arguments": { "values": { "type": "ndarray", "array": [ - 0.005, - 0.005 + [ + -15.5890625, + 19.586607882258054 + ], + [ + 0.54375, + -0.5556996340950149 + ], + [ + 13.30625, + -14.988554254040048 + ] ], "dtype": "float64" } } }, - "fluxes": null, + "redshift": 2.0, "fluxes_noise_map": null, - "time_delays": null, - "redshift": 2.0 + "time_delays_noise_map": null } } \ No newline at end of file diff --git a/dataset/cluster/test/point_datasets.csv b/dataset/cluster/test/point_datasets.csv index a460418f..bad7c205 100644 --- a/dataset/cluster/test/point_datasets.csv +++ b/dataset/cluster/test/point_datasets.csv @@ -1,5 +1,7 @@ name,y,x,positions_noise,redshift -point_0,1.0,0.0,0.005,1.0 -point_0,0.0,1.0,0.005,1.0 -point_1,1.0,0.0,0.005,2.0 -point_1,0.0,1.0,0.005,2.0 +point_0,-11.165625,-18.56902803281134,0.005,1.0 +point_0,-0.0390625,-0.12358904199840427,0.005,1.0 +point_0,3.00859375,23.4498930819527,0.005,1.0 +point_1,-15.5890625,19.586607882258054,0.005,2.0 +point_1,0.54375,-0.5556996340950149,0.005,2.0 +point_1,13.30625,-14.988554254040048,0.005,2.0 diff --git a/dataset/cluster/test/psf.fits b/dataset/cluster/test/psf.fits index 3d342eff..940efcd8 100644 Binary files a/dataset/cluster/test/psf.fits and b/dataset/cluster/test/psf.fits differ diff --git a/dataset/cluster/test/tracer.json b/dataset/cluster/test/tracer.json index 19b54a19..1a7f0e4a 100644 --- a/dataset/cluster/test/tracer.json +++ b/dataset/cluster/test/tracer.json @@ -14,22 +14,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 20.0, - "ra": 8.0, - "b0": 3.0, + "sigma": 330.0, + "H0": 67.66, + "r_cut": 20.0, + "r_core": 8.0, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 0.0, 0.0 ] - } + }, + "redshift_object": 0.5 } }, "bulge": { @@ -37,15 +41,15 @@ "class_path": "autogalaxy.profiles.light.standard.sersic.SersicSph", "arguments": { "effective_radius": 3.0, - "sersic_index": 4.0, - "intensity": 1.5, "centre": { "type": "tuple", "values": [ 0.0, 0.0 ] - } + }, + "sersic_index": 4.0, + "intensity": 1.5 } } } @@ -54,22 +58,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 12.0, - "ra": 5.0, - "b0": 1.2, + "sigma": 210.0, + "H0": 67.66, + "r_cut": 12.0, + "r_core": 5.0, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 10.0, 8.0 ] - } + }, + "redshift_object": 0.5 } }, "bulge": { @@ -77,15 +85,15 @@ "class_path": "autogalaxy.profiles.light.standard.sersic.SersicSph", "arguments": { "effective_radius": 1.5, - "sersic_index": 3.5, - "intensity": 0.8, "centre": { "type": "tuple", "values": [ 10.0, 8.0 ] - } + }, + "sersic_index": 3.5, + "intensity": 0.8 } } } @@ -94,22 +102,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 8.0, - "ra": 2.0, - "b0": 0.5, + "sigma": 135.0, + "H0": 67.66, + "r_cut": 8.0, + "r_core": 2.0, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -7.0, -4.0 ] - } + }, + "redshift_object": 0.5 } }, "bulge": { @@ -117,15 +129,15 @@ "class_path": "autogalaxy.profiles.light.standard.sersic.SersicSph", "arguments": { "effective_radius": 1.0, - "sersic_index": 3.0, - "intensity": 0.5, "centre": { "type": "tuple", "values": [ -7.0, -4.0 ] - } + }, + "sersic_index": 3.0, + "intensity": 0.5 } } } @@ -134,22 +146,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.12, + "sigma": 67.5980119451993, + "H0": 67.66, + "r_cut": 9.992797406132079, + "r_core": 0.09992797406132078, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 5.5, -6.5 ] - } + }, + "redshift_object": 0.5 } } } @@ -158,22 +174,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.096, + "sigma": 63.9302525824687, + "H0": 67.66, + "r_cut": 8.937829714197962, + "r_core": 0.0893782971419796, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -7.5, 3.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -182,22 +202,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.075, + "sigma": 60.10407640085654, + "H0": 67.66, + "r_cut": 7.9, + "r_core": 0.079, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 12.0, -5.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -206,22 +230,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.06, + "sigma": 56.84292592299587, + "H0": 67.66, + "r_cut": 7.065974808899336, + "r_core": 0.07065974808899335, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -4.0, -9.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -230,22 +258,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.048, + "sigma": 53.75872022286245, + "H0": 67.66, + "r_cut": 6.32, + "r_core": 0.0632, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 3.0, 13.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -254,22 +286,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.039, + "sigma": 51.03930638755519, + "H0": 67.66, + "r_cut": 5.696771015233104, + "r_core": 0.056967710152331034, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -14.0, 4.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -278,22 +314,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.03, + "sigma": 47.79901264117967, + "H0": 67.66, + "r_cut": 4.996398703066039, + "r_core": 0.04996398703066039, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 15.0, 9.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -302,22 +342,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.024, + "sigma": 45.20551512403241, + "H0": 67.66, + "r_cut": 4.468914857098981, + "r_core": 0.0446891485709898, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -9.0, -12.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -326,22 +370,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.018, + "sigma": 42.068472032638006, + "H0": 67.66, + "r_cut": 3.8701937935974215, + "r_core": 0.038701937935974214, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ 8.5, 5.5 ] - } + }, + "redshift_object": 0.5 } } } @@ -350,22 +398,26 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "mass": { "type": "instance", "class_path": "autogalaxy.profiles.mass.total.dual_pseudo_isothermal_mass.dPIEMassSph", "arguments": { - "rs": 10.0, - "ra": 0.1, - "b0": 0.015, + "sigma": 40.19401838263497, + "H0": 67.66, + "r_cut": 3.532987404449668, + "r_core": 0.035329874044496674, + "Om0": 0.30966, + "redshift_source": 2.0, "centre": { "type": "tuple", "values": [ -6.5, 11.0 ] - } + }, + "redshift_object": 0.5 } } } @@ -374,22 +426,22 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 0.5, + "label": "cls16", "dark": { "type": "instance", "class_path": "autogalaxy.profiles.mass.dark.nfw_mcr.NFWMCRLudlowSph", "arguments": { "redshift_source": 2.0, - "redshift_object": 0.5, - "mass_at_200": 1995262314968882.8, "centre": { "type": "tuple", "values": [ 0.0, 0.0 ] - } + }, + "mass_at_200": 1995262314968882.8, + "redshift_object": 0.5 } } } @@ -398,24 +450,16 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 1.0, + "label": "cls16", "bulge": { "type": "instance", "class_path": "autogalaxy.profiles.light.standard.sersic_core.SersicCore", "arguments": { + "alpha": 3.0, + "intensity": 2.0, "radius_break": 0.025, - "centre": { - "type": "tuple", - "values": [ - 0.3, - 0.5 - ] - }, - "sersic_index": 1.0, "gamma": 0.25, - "intensity": 2.0, - "alpha": 3.0, "effective_radius": 0.3, "ell_comps": { "type": "tuple", @@ -423,6 +467,14 @@ 0.0962250448649376, -0.05555555555555551 ] + }, + "sersic_index": 1.0, + "centre": { + "type": "tuple", + "values": [ + 0.3, + 0.5 + ] } } } @@ -432,24 +484,16 @@ "type": "instance", "class_path": "autogalaxy.galaxy.galaxy.Galaxy", "arguments": { - "label": "cls16", "redshift": 2.0, + "label": "cls16", "bulge": { "type": "instance", "class_path": "autogalaxy.profiles.light.standard.sersic_core.SersicCore", "arguments": { + "alpha": 3.0, + "intensity": 2.0, "radius_break": 0.025, - "centre": { - "type": "tuple", - "values": [ - -0.8, - 1.2 - ] - }, - "sersic_index": 1.0, "gamma": 0.25, - "intensity": 2.0, - "alpha": 3.0, "effective_radius": 0.3, "ell_comps": { "type": "tuple", @@ -457,6 +501,14 @@ 1.360718665719281e-17, -0.11111111111111108 ] + }, + "sersic_index": 1.0, + "centre": { + "type": "tuple", + "values": [ + -0.8, + 1.2 + ] } } } diff --git a/scripts/cluster/csv_api.py b/scripts/cluster/csv_api.py index b4fd86cb..a43492c2 100644 --- a/scripts/cluster/csv_api.py +++ b/scripts/cluster/csv_api.py @@ -49,13 +49,34 @@ """ mass_profiles = { "lens_0": { - "mass": al.mp.dPIEMassSph(centre=(0.0, 0.0), ra=8.0, rs=20.0, b0=3.0), + "mass": al.mp.dPIEMassSph( + centre=(0.0, 0.0), + sigma=330.0, + r_core=8.0, + r_cut=20.0, + redshift_object=0.5, + redshift_source=2.0, + ), }, "lens_1": { - "mass": al.mp.dPIEMassSph(centre=(10.0, 8.0), ra=5.0, rs=12.0, b0=1.2), + "mass": al.mp.dPIEMassSph( + centre=(10.0, 8.0), + sigma=210.0, + r_core=5.0, + r_cut=12.0, + redshift_object=0.5, + redshift_source=2.0, + ), }, "extra_0": { - "mass": al.mp.dPIEMassSph(centre=(-7.0, -4.0), ra=2.0, rs=8.0, b0=0.5), + "mass": al.mp.dPIEMassSph( + centre=(-7.0, -4.0), + sigma=135.0, + r_core=2.0, + r_cut=8.0, + redshift_object=0.5, + redshift_source=2.0, + ), }, "host_halo": { "dark": al.mp.NFWMCRLudlowSph( diff --git a/scripts/cluster/lenstool_parity.py b/scripts/cluster/lenstool_parity.py index f72a2bea..d0283f7c 100644 --- a/scripts/cluster/lenstool_parity.py +++ b/scripts/cluster/lenstool_parity.py @@ -2,9 +2,10 @@ Lenstool dPIE Parity Check ========================== -Validate the Lenstool-native dPIE parameterization (``dPIEMass.from_lenstool`` / -``dPIEMassSph.from_lenstool``) and the internal consistency of the dPIE port, so the -"PyAutoLens for Lenstool users" workflow can trust the parameter mapping end to end. +Validate the Lenstool-native dPIE parameterization (the default ``dPIEMass`` / ``dPIEMassSph`` +constructors and the general-cosmology ``dPIEMassB0.from_lenstool`` / ``dPIEMassB0Sph.from_lenstool`` +converters) and the internal consistency of the dPIE port, so the "PyAutoLens for Lenstool users" +workflow can trust the parameter mapping end to end. Conventions verified against the Lenstool C source (git-cral.univ-lyon1.fr/lenstool/lenstool): @@ -67,7 +68,7 @@ def print_leg(name, max_frac): sigma_lt = 1200.0 z_l, z_s = 0.375, 2.0 -mp_sph = al.mp.dPIEMassSph.from_lenstool( +mp_sph = al.mp.dPIEMassB0Sph.from_lenstool( sigma=sigma_lt, r_core=0.5, r_cut=40.0, @@ -95,11 +96,31 @@ def print_leg(name, max_frac): # Ellipticity: emass -> epot equals Lenstool's set_lens.c conversion. for emass in (0.05, 0.2, 0.4, 0.6): - mp_ell = al.mp.dPIEMass.from_lenstool(ellipticity=emass, angle_pos=30.0) + mp_ell = al.mp.dPIEMassB0.from_lenstool(ellipticity=emass, angle_pos=30.0) epot_lenstool = (1.0 - np.sqrt(1.0 - emass**2)) / emass assert abs(mp_ell._ellip() / epot_lenstool - 1.0) < 1e-10 print(" emass -> epot = (1-sqrt(1-e^2))/e = |ell_comps| OK for e in {0.05..0.6}") +# Default-class equivalence: the default (Lenstool-native) constructor with flat H0/Om0 +# must reproduce the from_lenstool conversion under the same background cosmology. +mp_default = al.mp.dPIEMassSph( + sigma=sigma_lt, + r_core=0.5, + r_cut=40.0, + redshift_object=z_l, + redshift_source=z_s, +) +mp_flat = al.mp.dPIEMassB0Sph.from_lenstool( + sigma=sigma_lt, + r_core=0.5, + r_cut=40.0, + redshift_object=z_l, + redshift_source=z_s, + cosmology=ag.cosmo.FlatLambdaCDM(), +) +assert abs(mp_default.b0 / mp_flat.b0 - 1.0) < 1e-10 +print(" default dPIEMassSph(sigma, r_core, r_cut) == dPIEMassB0Sph.from_lenstool OK") + """ __Leg 2: Spherical deflection vs convergence integral__ @@ -128,7 +149,7 @@ def print_leg(name, max_frac): """ print("Leg 3: analytic enclosed-convergence anchor (ra -> 0)") -mp_zero_core = al.mp.dPIEMassSph(centre=(0.0, 0.0), ra=1e-8, rs=25.0, b0=8.0) +mp_zero_core = al.mp.dPIEMassB0Sph(centre=(0.0, 0.0), ra=1e-8, rs=25.0, b0=8.0) max_frac = 0.0 for R in (0.5, 2.0, 10.0, 40.0): @@ -147,7 +168,7 @@ def print_leg(name, max_frac): """ print("Leg 4: elliptical deflections vs finite-difference potential gradient") -mp_ell = al.mp.dPIEMass.from_lenstool( +mp_ell = al.mp.dPIEMassB0.from_lenstool( ellipticity=0.4, angle_pos=20.0, sigma=800.0, @@ -192,7 +213,7 @@ def print_leg(name, max_frac): """ print("Leg 5: analytical hessian vs deflection finite differences (profile frame)") -mp_ell_frame = al.mp.dPIEMass.from_lenstool( +mp_ell_frame = al.mp.dPIEMassB0.from_lenstool( ellipticity=0.4, angle_pos=0.0, sigma=800.0, @@ -243,7 +264,7 @@ def print_leg(name, max_frac): b0_target = 5.2 sigma_from_b0 = C_KM_S * np.sqrt(b0_target / (6.0 * 648000.0 * (d_ls / d_s))) -mp_ref = al.mp.dPIEMassSph.from_lenstool( +mp_ref = al.mp.dPIEMassB0Sph.from_lenstool( centre=(-0.7, 0.5), sigma=sigma_from_b0, r_core=2.0, diff --git a/scripts/cluster/likelihood_sanity.py b/scripts/cluster/likelihood_sanity.py index 936a17bf..41e6f17a 100644 --- a/scripts/cluster/likelihood_sanity.py +++ b/scripts/cluster/likelihood_sanity.py @@ -8,7 +8,7 @@ - Compute the source-plane chi² (``FitPositionsSource`` — ray-trace observed positions back, measure scatter relative to the truth Point centre) against the truth model and at a sweep of perturbed mass parameters. - - Perturb each numeric mass parameter (``ra``, ``rs``, ``b0`` on every dPIE galaxy; ``mass_at_200`` + - Perturb each numeric mass parameter (``sigma``, ``r_core``, ``r_cut`` on every dPIE galaxy; ``mass_at_200`` on the NFW host halo) by ε ∈ {-0.2, -0.1, -0.05, -0.01, -0.001, 0, 0.001, 0.01, 0.05, 0.1, 0.2}. Assert: a) For LARGE perturbations (|ε| ≥ 0.10) the truth (ε=0) chi² is strictly less than the @@ -74,7 +74,8 @@ The truth tracer is rebuilt from the CSVs the simulator consumed/produced, exactly as ``simulator.py`` builds it. Scaling-tier members come from the legacy 3-column CSV via the -``b0 = scaling_factor * luminosity ** scaling_exponent`` truth relation. +reference-anchored truth relation ``sigma = sigma_ref * (L / L_ref) ** 0.25``, +``r_core / r_cut ∝ (L / L_ref) ** 0.5`` (Lenstool convention). """ mass_table = al.galaxy_models_from_csv(DATASET_PATH / "mass.csv", family="mass") light_table = al.galaxy_models_from_csv(DATASET_PATH / "light.csv", family="light") @@ -95,23 +96,31 @@ scaling_galaxies_centres = list(scaling_galaxies_table.centres.in_list) scaling_galaxies_luminosities = scaling_galaxies_table.luminosities -SCALING_FACTOR_TRUTH = 0.3 -SCALING_EXPONENT_TRUTH = 1.0 -SCALING_RA = 0.1 -SCALING_RS = 10.0 +SCALING_SIGMA_REF_TRUTH = 85.0 +SCALING_SIGMA_EXPONENT = 0.25 +SCALING_RADIUS_EXPONENT = 0.5 +SCALING_R_CORE_REF = 0.158 +SCALING_R_CUT_REF = 15.8 +REFERENCE_LUMINOSITY = 1.0 +REDSHIFT_SOURCE_MAX = 2.0 def _build_scaling_galaxies( - scaling_factor=SCALING_FACTOR_TRUTH, scaling_exponent=SCALING_EXPONENT_TRUTH + sigma_ref=SCALING_SIGMA_REF_TRUTH, sigma_exponent=SCALING_SIGMA_EXPONENT ): return [ al.Galaxy( redshift=0.5, mass=al.mp.dPIEMassSph( centre=tuple(centre), - ra=SCALING_RA, - rs=SCALING_RS, - b0=scaling_factor * luminosity**scaling_exponent, + sigma=sigma_ref + * (luminosity / REFERENCE_LUMINOSITY) ** sigma_exponent, + r_core=SCALING_R_CORE_REF + * (luminosity / REFERENCE_LUMINOSITY) ** SCALING_RADIUS_EXPONENT, + r_cut=SCALING_R_CUT_REF + * (luminosity / REFERENCE_LUMINOSITY) ** SCALING_RADIUS_EXPONENT, + redshift_object=0.5, + redshift_source=REDSHIFT_SOURCE_MAX, ), ) for centre, luminosity in zip( @@ -256,8 +265,8 @@ def image_chi_squared(tracer, dataset_list, source_galaxies): """ __Perturbation Sweep__ -For each numeric mass parameter, evaluate chi² at a small grid of relative perturbations. ``ra``, -``rs``, ``b0`` are perturbed multiplicatively in linear space (ε relative to truth). ``mass_at_200`` +For each numeric mass parameter, evaluate chi² at a small grid of relative perturbations. ``sigma``, +``r_core``, ``r_cut`` are perturbed multiplicatively in linear space (ε relative to truth). ``mass_at_200`` is also perturbed multiplicatively but the effect on lensing is super-linear, so the same ε grid produces a different chi² response. """ @@ -269,10 +278,26 @@ def image_chi_squared(tracer, dataset_list, source_galaxies): def _perturb_dpie(galaxy, param_name, epsilon): - """Return a copy of ``galaxy`` with ``mass.`` perturbed by factor (1+epsilon).""" + """Return a copy of ``galaxy`` with ``mass.`` perturbed by factor (1+epsilon). + + The Lenstool-parameterized dPIE derives its internal lens strength ``b0`` from ``sigma`` + and the redshifts in ``__init__``, so the profile must be REBUILT with the perturbed + constructor argument — mutating the attribute would not propagate to the deflections. + """ + mass = galaxy.mass + kwargs = dict( + centre=mass.centre, + sigma=mass.sigma, + r_core=mass.r_core, + r_cut=mass.r_cut, + redshift_object=mass.redshift_object, + redshift_source=mass.redshift_source, + H0=mass.H0, + Om0=mass.Om0, + ) + kwargs[param_name] = kwargs[param_name] * (1.0 + epsilon) new_galaxy = copy.deepcopy(galaxy) - truth = getattr(new_galaxy.mass, param_name) - setattr(new_galaxy.mass, param_name, truth * (1.0 + epsilon)) + new_galaxy.mass = al.mp.dPIEMassSph(**kwargs) return new_galaxy @@ -317,7 +342,7 @@ def build(epsilon): PERTURBATIONS = [] for idx, label in enumerate(GALAXY_LABELS): - for param in ("ra", "rs", "b0"): + for param in ("sigma", "r_core", "r_cut"): PERTURBATIONS.append((f"{label}.mass.{param}", _make_dpie_builder(idx, param))) PERTURBATIONS.append(("host_halo.dark.mass_at_200", _make_nfw_builder())) diff --git a/scripts/cluster/simulator.py b/scripts/cluster/simulator.py index 2ab98b7f..03a06c94 100644 --- a/scripts/cluster/simulator.py +++ b/scripts/cluster/simulator.py @@ -64,27 +64,36 @@ """ __Scaling Galaxies__ -The 10 lower-mass members each get a ``dPIEMassSph`` derived from the scaling relation -``b0 = scaling_factor * luminosity ** scaling_exponent``. Core/truncation radii are held fixed -across the tier — matches the truth values used by ``autolens_workspace/scripts/cluster/simulator.py``. +The 10 lower-mass members each get a ``dPIEMassSph`` (Lenstool-native parameters) derived from the +reference-anchored scaling relation ``sigma = sigma_ref * (L / L_ref) ** 0.25``, +``r_core / r_cut ∝ (L / L_ref) ** 0.5`` — matches the truth convention used by +``autolens_workspace/scripts/cluster/simulator.py``. """ scaling_galaxies_table = al.galaxy_table_from_csv(dataset_path / "scaling_galaxies.csv") scaling_galaxies_centres = list(scaling_galaxies_table.centres.in_list) scaling_galaxies_luminosities = scaling_galaxies_table.luminosities -scaling_factor_truth = 0.3 -scaling_exponent_truth = 1.0 -scaling_ra = 0.1 -scaling_rs = 10.0 +scaling_sigma_ref_truth = 85.0 +scaling_sigma_exponent = 0.25 +scaling_radius_exponent = 0.5 +scaling_r_core_ref = 0.158 +scaling_r_cut_ref = 15.8 +reference_luminosity = 1.0 +redshift_source_max = max(g.redshift for g in source_galaxies) scaling_galaxies = [] for centre, luminosity in zip(scaling_galaxies_centres, scaling_galaxies_luminosities): - b0 = scaling_factor_truth * luminosity**scaling_exponent_truth + ratio = luminosity / reference_luminosity scaling_galaxies.append( al.Galaxy( redshift=0.5, mass=al.mp.dPIEMassSph( - centre=tuple(centre), ra=scaling_ra, rs=scaling_rs, b0=b0 + centre=tuple(centre), + sigma=scaling_sigma_ref_truth * ratio**scaling_sigma_exponent, + r_core=scaling_r_core_ref * ratio**scaling_radius_exponent, + r_cut=scaling_r_cut_ref * ratio**scaling_radius_exponent, + redshift_object=0.5, + redshift_source=redshift_source_max, ), ) ) @@ -124,9 +133,13 @@ mass=af.Model( al.mp.dPIEMassSph, centre=g.mass.centre, - ra=g.mass.ra, - rs=g.mass.rs, - b0=g.mass.b0, + sigma=g.mass.sigma, + r_core=g.mass.r_core, + r_cut=g.mass.r_cut, + redshift_object=g.mass.redshift_object, + redshift_source=g.mass.redshift_source, + H0=g.mass.H0, + Om0=g.mass.Om0, ), ) for g in main_lens_galaxies diff --git a/scripts/mass/total.py b/scripts/mass/total.py index 90879666..d4af3b30 100644 --- a/scripts/mass/total.py +++ b/scripts/mass/total.py @@ -253,8 +253,8 @@ """ run_param_sweep( - "dPIEMass", - ag.mp.dPIEMass, + "dPIEMassB0", + ag.mp.dPIEMassB0, [ dict(centre=(0.0, 0.0), ell_comps=(0.1, 0.05), ra=0.02, rs=2.5, b0=0.15), dict(centre=(0.0, 0.0), ell_comps=(0.1, 0.05), ra=0.1, rs=5.0, b0=0.3), @@ -264,11 +264,51 @@ results, ) +run_param_sweep( + "dPIEMassB0Sph", + ag.mp.dPIEMassB0Sph, + [ + dict(centre=(0.0, 0.0), ra=0.02, rs=2.5, b0=0.15), + ], + grid, + tol, + results, +) + +# Default (Lenstool-native) parameterization — same physics reached through the +# sigma / r_core / r_cut constructor. +run_param_sweep( + "dPIEMass", + ag.mp.dPIEMass, + [ + dict( + centre=(0.0, 0.0), + ellipticity=0.1, + angle_pos=30.0, + sigma=150.0, + r_core=0.02, + r_cut=2.5, + redshift_object=0.5, + redshift_source=1.0, + ), + ], + grid, + tol, + results, +) + run_param_sweep( "dPIEMassSph", ag.mp.dPIEMassSph, [ - dict(centre=(0.0, 0.0), ra=0.02, rs=2.5, b0=0.15), + dict( + centre=(0.0, 0.0), + sigma=150.0, + r_core=0.02, + r_cut=2.5, + redshift_object=0.5, + redshift_source=1.0, + ), ], grid, tol,