Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracer model more tests and in sync with main #536

Merged
merged 41 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
441045e
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Sep 12, 2023
fd3f872
Merge pull request #514 from lenstronomy/pre-commit-ci-update-config
ajshajib Sep 24, 2023
aba5d71
ready for minor release 1.11.4
sibirrer Sep 27, 2023
3d6d4fc
Merge branch 'lenstronomy:main' into main
sibirrer Sep 27, 2023
b143b74
Merge pull request #523 from sibirrer/main
sibirrer Sep 27, 2023
f63c293
fix bug in luminosity weighted kinematics
sibirrer Sep 28, 2023
072e217
Debug findOverlap parantheses of image_util.py
Maverick-Oh Sep 28, 2023
d60cdfd
deleting unnecessary new lines
Maverick-Oh Sep 28, 2023
46f7ebd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 28, 2023
dc25a6c
Merge pull request #524 from Maverick-Oh/patch-1
sibirrer Sep 28, 2023
fcce083
Merge branch 'lenstronomy:main' into main
sibirrer Sep 28, 2023
aa07739
minor test improvements
sibirrer Sep 28, 2023
1e30a3f
ready for release 1.11.5
sibirrer Sep 28, 2023
6aa98d6
Merge pull request #525 from sibirrer/main
sibirrer Sep 28, 2023
f1a43bd
minor test changes
sibirrer Oct 3, 2023
a834395
adding description on how to add new lens model profiles
sibirrer Oct 5, 2023
aeb35a7
removed todos
sibirrer Oct 5, 2023
aa574c8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 5, 2023
60e96f5
Merge pull request #527 from sibirrer/main
sibirrer Oct 5, 2023
f368f1b
removed redundant calculation in NFW deflection angle calculation, cr…
sibirrer Oct 13, 2023
1b76039
updated lens model implementation with testing
sibirrer Oct 16, 2023
c49ccd9
Merge branch 'lenstronomy:main' into main
sibirrer Oct 16, 2023
b309bf9
Merge pull request #530 from sibirrer/main
sibirrer Oct 17, 2023
6eecf70
finitial commit for radial interpolation
sibirrer Oct 20, 2023
effd835
centered coordinate grid function
sibirrer Oct 20, 2023
fc712d7
centered coordinate grid function
sibirrer Oct 20, 2023
5dd18c3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 20, 2023
4715258
Merge pull request #532 from sibirrer/simAPI_coordinates
sibirrer Oct 20, 2023
acb8a5e
bug fixed
sibirrer Oct 20, 2023
70355ee
profile in place and tested
sibirrer Oct 21, 2023
b0fe858
Merge branch 'main' into simAPI_coordinates
sibirrer Oct 21, 2023
e639f29
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 21, 2023
3f4958a
Merge remote-tracking branch 'origin/simAPI_coordinates' into simAPI_…
sibirrer Oct 21, 2023
56c5c3f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 21, 2023
85ee534
Merge pull request #533 from sibirrer/simAPI_coordinates
sibirrer Oct 21, 2023
8017411
build requirements in readthedocs updated
sibirrer Oct 21, 2023
1a8d67f
further readthedocs configuration
sibirrer Oct 21, 2023
00bd715
Merge branch 'main' into tracer_model
sibirrer Oct 22, 2023
f1f4c48
tests for linear profile added
sibirrer Oct 22, 2023
0df311f
Merge branch 'lenstronomy:tracer_model' into tracer_model
sibirrer Oct 22, 2023
c80f51d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ci:

repos:
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black
# It is recommended to specify the latest version of Python
Expand All @@ -21,7 +21,7 @@ repos:
# https://pre-commit.com/#top_level-default_language_version
language_version: python3
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black-jupyter
language_version: python3
Expand Down
12 changes: 10 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# You can also specify other tool versions:
# nodejs: "20"
# rust: "1.70"
# golang: "1.20"

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
Expand All @@ -18,7 +28,5 @@ formats: all

# Optionally set the version of Python and requirements required to build your docs
python:
version: "3.8"
install:
#- requirements: requirements.txt
- requirements: requirements.txt
12 changes: 11 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,14 @@ History
* cored truncated NFW profile
* SkiNN interface
* faster and more reliable Einstein radius computation
* Cobaya interface
* Cobaya interface

1.11.4 (2023-09-27)
+++++++++++++++++++
* Cobaya not required to run FittingSequence
* Galkin with luminosity-weighted velocity dispersion calculation

1.11.5 (2023-09-28)
+++++++++++++++++++
* bug fix in findOverlap function
* bug fix in luminosity-0weighted celocity dispersion calculation
2 changes: 1 addition & 1 deletion lenstronomy/GalKin/numeric_kinematics.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def lum_weighted_vel_disp(self, R, kwargs_mass, kwargs_light, kwargs_anisotropy)
)
# azimuthal averaging
I_R_sigma2 = np.sum(I_R_sigma2_rad * r_rad)
I_R = np.sum(I_R_rad)
I_R = np.sum(I_R_rad * r_rad)
# return in units km/s
sigma_s2 = I_R_sigma2 / I_R
sigma = np.sqrt(sigma_s2) / 1000.0
Expand Down
20 changes: 19 additions & 1 deletion lenstronomy/LensModel/Profiles/base_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,25 @@
class LensProfileBase(object):
"""This class acts as the base class of all lens model functions and indicates raise
statements and default outputs if these functions are not defined in the specific
lens model class."""
lens model class.
To implement a new lens model profile you should:
1. make a new python file in this folder
2. create a class inheriting this class; YourModel(LensProfileBase)
3. write new definitions following the same input and output conventions as this base class
function(x, y, <other parameters>)
derivatives(x, y, <other parameters>)
hessian(x, y, <other parameters>)
4. set the variables for sampling the new profile
param_names = ["param1", "param2", ...]
lower_limit_default = {"param1": value, "param2: value, ...}
upper_limit_default = {"param1": value, "param2: value, ...}
5. give the new profile a meaningful name and add it in the LensModel.profile_list_base class
6. write test functions in the test/test_LensModel/test_Profiles folder with a new file with test_<profile name>.py
With that, you should be good to go and import and use it for any purpose.
Further definitions in the class are optional and only used for certain applications (such as kinematics)
"""

def __init__(self, *args, **kwargs):
self._static = False
Expand Down
2 changes: 1 addition & 1 deletion lenstronomy/LensModel/Profiles/nfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def nfwAlpha(self, R, Rs, rho0, ax_x, ax_y):
R = np.maximum(R, 0.00000001)
x = R / Rs
gx = self.g_(x)
a = 4 * rho0 * Rs * R * gx / x**2 / R
a = 4 * rho0 * Rs * gx / x**2
return a * ax_x, a * ax_y

def nfwGamma(self, R, Rs, rho0, ax_x, ax_y):
Expand Down
199 changes: 199 additions & 0 deletions lenstronomy/LensModel/Profiles/radial_interpolated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import numpy as np
from lenstronomy.LensModel.Profiles.base_profile import LensProfileBase
from lenstronomy.Util import param_util
from scipy.interpolate import interp1d
from scipy import integrate

__all__ = ["RadialInterpolate"]


class RadialInterpolate(LensProfileBase):
"""Radially interpolated profile with azimuthal symmetry."""

param_names = [
"r_bin",
"kappa_r",
"center_x",
"center_y",
]
lower_limit_default = {}
upper_limit_default = {}

def function(
self,
x,
y,
r_bin=None,
kappa_r=None,
center_x=0,
center_y=0,
):
"""Lensing potential (only needed for specific calculations, such as time
delays)

:param x: x-coordinate (angular position), float or numpy array
:param y: y-coordinate (angular position), float or numpy array
:param r_bin: radial bins for which convergence values are provided
:type r_bin: array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:param center_x: x-position of center of radial density profile
:type center_x: float
:param center_y: y-position of center of radial density profile
:type center_y: float
:return: lensing potential
"""
r, phi = param_util.cart2polar(x, y, center_x=center_x, center_y=center_y)
# -\int alpha(r) dr from 0 to r
pot = self._potential_r(r, r_bin, kappa_r)
return pot

def derivatives(
self,
x,
y,
r_bin=None,
kappa_r=None,
center_x=0,
center_y=0,
):
"""Returns df/dx and df/dy of the function.

:param x: x-coordinate (angular position), float or numpy array
:param y: y-coordinate (angular position), float or numpy array
:param r_bin: radial bins for which convergence values are provided
:type r_bin: array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:param center_x: x-position of center of radial density profile
:type center_x: float
:param center_y: y-position of center of radial density profile
:type center_y: float
:return: f_x, f_y at interpolated positions (x, y)
"""
x_ = x - center_x
y_ = y - center_y
r = np.maximum(np.sqrt(x_**2 + y_**2), 10 ** (-10))
alpha = self.alpha(r, r_bin, kappa_r)
return alpha * x_ / r, alpha * y_ / r

def hessian(
self,
x,
y,
r_bin=None,
kappa_r=None,
center_x=0,
center_y=0,
):
"""Returns Hessian matrix of function d^2f/dx^2, d^2/dxdy, d^2/dydx, d^f/dy^2.

:param x: x-coordinate (angular position), float or numpy array
:param y: y-coordinate (angular position), float or numpy array
:param r_bin: radial bins for which convergence values are provided
:type r_bin: array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:param center_x: x-position of center of radial density profile
:type center_x: float
:param center_y: y-position of center of radial density profile
:type center_y: float
:return: f_xx, f_xy, f_yx, f_yy at interpolated positions (x, y)
"""
r, phi = param_util.cart2polar(x, y, center_x=center_x, center_y=center_y)
r = np.maximum(r, 10 ** (-10))
kappa = self._kappa_r_interp(r, r_bin, kappa_r)
# shear in the spherical case is the average convergence enclosed minus the convergence at the radius
# source: Kaiser 1995
gamma = 1 * (self._mass_enclosed(r, r_bin, kappa) / (np.pi * r**2) - kappa)
# turn in to vector for gamma and cartesian derivatives
gamma1 = -np.cos(2.0 * phi) * gamma
gamma2 = -np.sin(2.0 * phi) * gamma
f_xx = kappa + gamma1
f_yy = kappa - gamma1
f_xy = gamma2

return f_xx, f_xy, f_xy, f_yy

def alpha(self, r, r_bin, kappa_r):
"""Radial deflection angle m(<r) / r / pi.

:param r: radius from center
:param r_bin: radial bins for which convergence values are provided
:type r_bin: array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:return: radial deflection angle
"""
r_ = np.maximum(r, 10 ** (-10))
return self._mass_enclosed(r, r_bin, kappa_r) / r_ / np.pi

def _kappa_r_interp(self, r, r_bin, kappa_r):
"""Calls interpolated kappa(r)

:param r: radius
:param r_bin: radial bins for which convergence values are provided
:type r_bin: numpy array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:return: kappa(r)
"""
if not hasattr(self, "_interp_kappa"):
self._interp_kappa = interp1d(
r_bin, kappa_r, fill_value=(kappa_r[0], kappa_r[-1]), bounds_error=False
)
return self._interp_kappa(r)

def _mass_enclosed(self, r, r_bin, kappa_r):
"""Convergence enclosed a radius.

:param r: radius
:param r_bin: radial bins for which convergence values are provided
:type r_bin: numpy array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:return: integrated convergence within radius <r
"""
if not hasattr(self, "_interp_m_enclosed"):

def _integrand(x):
return x * 2 * np.pi * self._kappa_r_interp(x, r_bin, kappa_r)

m_slice_list = []
r_min = 0
for r_ in r_bin:
m_slice, _ = integrate.quad(_integrand, r_min, r_)
m_slice_list.append(m_slice)
r_min = r_
m_r = np.cumsum(m_slice_list)
self._interp_m_enclosed = interp1d(
r_bin, m_r, fill_value=(0, m_r[-1]), bounds_error=False
)
return self._interp_m_enclosed(r)

def _potential_r(self, r, r_bin, kappa_r):
"""Convergence enclosed a radius.

:param r: radius
:param r_bin: radial bins for which convergence values are provided
:type r_bin: numpy array
:param kappa_r: convergence values corresponding to the r_bin radii
:type kappa_r: array of same size as r_bin
:return: integrated convergence within radius <r
"""
if not hasattr(self, "_interp_potential"):

def _integrand(x):
return self.alpha(x, r_bin, kappa_r)

pot_slice_list = []
r_min = 0
for r_ in r_bin:
pot_slice, _ = integrate.quad(_integrand, r_min, r_)
pot_slice_list.append(pot_slice)
r_min = r_
pot_r = np.cumsum(pot_slice_list)
self._interp_potential = interp1d(
r_bin, pot_r, fill_value=(0, pot_r[-1]), bounds_error=False
)
return self._interp_potential(r)
12 changes: 10 additions & 2 deletions lenstronomy/LensModel/profile_list_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"HESSIAN",
"INTERPOL",
"INTERPOL_SCALED",
"LOS",
"RADIAL_INTERPOL" "LOS",
"LOS_MINIMAL",
"MULTIPOLE",
"MULTI_GAUSSIAN_KAPPA",
Expand Down Expand Up @@ -156,7 +156,7 @@ def _load_model_instances(
"CTNFW_GAUSS_DEC",
"INTERPOL",
"INTERPOL_SCALED",
"NIE",
"RADIAL_INTERPOL" "NIE",
"NIE_SIMPLE",
]:
lensmodel_class = self._import_class(
Expand Down Expand Up @@ -447,6 +447,14 @@ def _import_class(
from lenstronomy.LensModel.Profiles.interpol import InterpolScaled

return InterpolScaled(**kwargs_interp)

elif lens_type == "RADIAL_INTERPOL":
from lenstronomy.LensModel.Profiles.radial_interpolated import (
RadialInterpolate,
)

return RadialInterpolate()

elif lens_type == "SHAPELETS_POLAR":
from lenstronomy.LensModel.Profiles.shapelet_pot_polar import PolarShapelets

Expand Down
4 changes: 2 additions & 2 deletions lenstronomy/Util/image_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ def findOverlap(x_mins, y_mins, min_distance):
pass
else:
for j in range(0, i):
if abs(
x_mins[i] - x_mins[j] < min_distance
if (
abs(x_mins[i] - x_mins[j]) < min_distance
and abs(y_mins[i] - y_mins[j]) < min_distance
):
idex.append(i)
Expand Down
26 changes: 26 additions & 0 deletions lenstronomy/Util/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,32 @@ def make_grid_transformed(numPix, Mpix2Angle):
return ra_grid, dec_grid


def centered_coordinate_system(num_pix, transform_pix2angle):
"""Returns dictionary for Coordinate Grid such that (0,0) is centered with given
input orientation coordinate transformation matrix.

:param num_pix: number of pixels
:type num_pix: int
:param transform_pix2angle: transformation matrix (2x2) of pixels into coordinate
displacements
:return: dict with ra_at_xy_0, dec_at_xy_0, transfrom_pix2angle
"""
pix_center = (num_pix - 1) / 2
ra_center = (
pix_center * transform_pix2angle[0, 0] + pix_center * transform_pix2angle[0, 1]
)
dec_center = (
pix_center * transform_pix2angle[1, 0] + pix_center * transform_pix2angle[1, 1]
)

kwargs_grid = {
"ra_at_xy_0": -ra_center,
"dec_at_xy_0": -dec_center,
"transform_pix2angle": transform_pix2angle,
}
return kwargs_grid


@export
def make_grid_with_coordtransform(
numPix,
Expand Down
2 changes: 1 addition & 1 deletion lenstronomy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__author__ = "lenstronomy developers"
__email__ = "lenstronomy-dev@googlegroups.com"
__version__ = "1.11.3"
__version__ = "1.11.5"
__credits__ = "ETH Zurich, UCLA, Stanford, Stony Brook"

from .Util.package_util import short, laconic