Source code for lightcurvelynx.effects.microlensing

"""An effect that adds microlensing magnification."""

import numpy as np
from citation_compass import CiteClass

from lightcurvelynx.effects.effect_model import EffectModel
from lightcurvelynx.math_nodes.given_sampler import BinarySampler


[docs] class Microlensing(EffectModel, CiteClass): """A simple microlensing effect that can be applied to basic models. For more complex models, such as those blended by the microlensing event, it is recommended to create a new physical model. This model is a pure Paczynski/point-source point-lens (PSPL) model, without any additional effects. They can be added later. At the moment no values are parametrized, but they can be in the future. Values that should be parametrized are: * lens_mass (M_L) * lens_distance (D_L) * source_distance (D_S) * relative_proper_motion (mu_rel, mu_LS) * source_radius (R_S) References ---------- * V. Bozza, MNRAS 408 (2010) 2188: general algorithm for binary lensing; * V. Bozza, E. Bachelet, F. Bartolic, T. Heintz, A. Hoag, M. Hundertmark, MNRAS 479 (2018) 5157: BinaryMag2 function, Extended-Source-Point-Lens methods; * V. Bozza, E. Khalouei and E. Bachelet, MNRAS 505 (2021) 126: astrometry, generalized limb darkening, Keplerian orbital motion; * V. Bozza, v. Saggese, G. Covone, P. Rota & J. Zhang, A&A 694 (2025) 219: multiple lenses. Attributes ---------- VBM : VBMicrolensing The microlensing model. Parameters ---------- microlensing_t0 : parameter The time of the microlensing peak, in days. u_0 : parameter Impact parameter, distance from the source at time of peak in Einstein radii. t_E : parameter Einstein timescale, in days. probability : float, optional The probability of the microlensing event occurring. Default: 1.0 **kwargs : dict, optional Any additional keyword arguments. """ def __init__(self, microlensing_t0, u_0, t_E, probability=1.0, **kwargs): super().__init__(**kwargs, rest_frame=False) self.add_effect_parameter("microlensing_t0", microlensing_t0) self.add_effect_parameter("u_0", u_0) self.add_effect_parameter("t_E", t_E) # Add a parameter that indicates whether or not we apply microlensing that # is drawn from a distribution with the given probability. if probability < 1.0: self.add_effect_parameter("apply_microlensing", BinarySampler(probability)) else: # Don't bother to add another node if we will always apply it. self.add_effect_parameter("apply_microlensing", True) # Create the microlensing model once. try: import VBMicrolensing except ImportError as err: # pragma: no cover raise ImportError( "VBMicrolensing package is not installed by default. To use the microlensing effect, " "please install it. For example, you can install it with `pip install VBMicrolensing`." ) from err
[docs] self.VBM = VBMicrolensing.VBMicrolensing()
[docs] def apply( self, flux_density, times=None, wavelengths=None, *, apply_microlensing=None, microlensing_t0=None, u_0=None, t_E=None, **kwargs, ): """Apply the effect to observations (flux_density values). Parameters ---------- flux_density : numpy.ndarray A length T X N matrix of flux density values (in nJy). times : numpy.ndarray, optional A length T array of times (in MJD). wavelengths : numpy.ndarray, optional A length N array of wavelengths (in angstroms). Not used for this effect. apply_microlensing : bool Whether or not to apply microlensing. microlensing_t0 : float The time of the microlensing peak, in days. u_0 : float Impact parameter, distance from the source at time of peak in Einstein radii. t_E : float Einstein timescale, in days. **kwargs : `dict`, optional Any additional keyword arguments, including any additional parameters needed to apply the effect. Returns ------- flux_density : numpy.ndarray A length T x N matrix of flux densities after the effect is applied (in nJy). """ # Skip the microlensing application if needed. if not apply_microlensing: return flux_density if microlensing_t0 is None: # pragma: no cover raise ValueError("microlensing_t0 must be provided") if u_0 is None: # pragma: no cover raise ValueError("u_0 must be provided") if t_E is None: # pragma: no cover raise ValueError("t_E must be provided") # Array of parameters # Note that VBMicrolensing requires some parameters # in log space, as per example: # https://github.com/valboz/VBMicrolensing/blob/main/docs/python/LightCurves.md pr = [np.log(u_0), np.log(t_E), microlensing_t0] # Calculates the PSPL magnification at different times with parameters in pr # Attention: VBMicrolensing assumes that times is an np.array or a list. vbm_results = self.VBM.PSPLLightCurve(pr, times) # array of magnifications at each time in time_stamp magnifications = np.asarray(vbm_results[0]) flux_density = flux_density * magnifications[:, np.newaxis] return flux_density
[docs] def apply_bandflux( self, bandfluxes, *, apply_microlensing=None, microlensing_t0=None, u_0=None, t_E=None, times=None, filters=None, **kwargs, ): """Apply the effect to band fluxes. Parameters ---------- bandfluxes : numpy.ndarray A length T array of band fluxes (in nJy). times : numpy.ndarray, optional A length T array of times (in MJD). filters : numpy.ndarray, optional A length N array of filters. If not provided, the effect is applied to all band fluxes. apply_microlensing : bool Whether or not to apply microlensing. microlensing_t0 : float The time of the microlensing peak, in days. u_0 : float Impact parameter, distance from the source at time of peak in Einstein radii. t_E : float Einstein timescale, in days. **kwargs : `dict`, optional Any additional keyword arguments, including any additional parameters needed to apply the effect. Returns ------- bandfluxes : numpy.ndarray A length T array of band fluxes after the effect is applied (in nJy). """ # If we do not apply microlensing, we can skip the entire computation. if not apply_microlensing: return bandfluxes if microlensing_t0 is None: # pragma: no cover raise ValueError("microlensing_t0 must be provided") if u_0 is None: # pragma: no cover raise ValueError("u_0 must be provided") if t_E is None: # pragma: no cover raise ValueError("t_E must be provided") # Array of parameters # Note that VBMicrolensing requires some parameters # in log space, as per example: # https://github.com/valboz/VBMicrolensing/blob/main/docs/python/LightCurves.md pr = [np.log(u_0), np.log(t_E), microlensing_t0] # Calculates the PSPL magnification at different times with parameters in pr # Attention: VBMicrolensing assumes that times is an np.array or a list. vbm_results = self.VBM.PSPLLightCurve(pr, times) # array of magnifications at each time in time_stamp bandfluxes = bandfluxes * np.asarray(vbm_results[0]) return bandfluxes