MicroLIA_Sim.microlensing ========================= .. py:module:: MicroLIA_Sim.microlensing Attributes ---------- .. autoapisummary:: MicroLIA_Sim.microlensing.ZERO_POINT MicroLIA_Sim.microlensing.EXPOSURE_TIME MicroLIA_Sim.microlensing.MJD_OFFSET MicroLIA_Sim.microlensing.MODEL_SPECS MicroLIA_Sim.microlensing.m_nfw_inner MicroLIA_Sim.microlensing.dm_nfw_inner MicroLIA_Sim.microlensing.m_boson_inner MicroLIA_Sim.microlensing.dm_boson_inner MicroLIA_Sim.microlensing.NFW_LOADED MicroLIA_Sim.microlensing.BS_LOADED MicroLIA_Sim.microlensing._NFW_TABLE MicroLIA_Sim.microlensing._BS_TABLE Classes ------- .. autoapisummary:: MicroLIA_Sim.microlensing.ModelSpec MicroLIA_Sim.microlensing.ExtendedLensModel MicroLIA_Sim.microlensing.NFWmodel MicroLIA_Sim.microlensing.BSmodel Functions --------- .. autoapisummary:: MicroLIA_Sim.microlensing.mag2nJy MicroLIA_Sim.microlensing.flux2mag MicroLIA_Sim.microlensing.abmag_to_njy MicroLIA_Sim.microlensing.njy_to_abmag MicroLIA_Sim.microlensing.t_m_boundaries MicroLIA_Sim.microlensing.describe_model_requirements MicroLIA_Sim.microlensing._normalize_model_type MicroLIA_Sim.microlensing.normalize_model_params MicroLIA_Sim.microlensing.validate_model_params MicroLIA_Sim.microlensing.validate_parallax MicroLIA_Sim.microlensing.validate_photometry MicroLIA_Sim.microlensing.load_and_interpolate_mass_function MicroLIA_Sim.microlensing.load_custom_extended_lens_tables MicroLIA_Sim.microlensing.calculate_magnification MicroLIA_Sim.microlensing.m_nfw MicroLIA_Sim.microlensing.dm_nfw MicroLIA_Sim.microlensing.m_boson MicroLIA_Sim.microlensing.dm_boson MicroLIA_Sim.microlensing.build_time_grid_jd MicroLIA_Sim.microlensing._compute_fsource_fblend_for_band MicroLIA_Sim.microlensing.simulate_perfect_event MicroLIA_Sim.microlensing.write_lightcurves_txt MicroLIA_Sim.microlensing.plot_lightcurves_mag Module Contents --------------- .. py:data:: ZERO_POINT :value: 31.4 .. py:data:: EXPOSURE_TIME :value: 1.0 .. py:data:: MJD_OFFSET :value: 2400000.5 .. py:function:: mag2nJy(mag: float | numpy.ndarray) -> float | numpy.ndarray Convert AB magnitude(s) to flux density in nanoJanskys (nJy). This uses the module-level ``ZERO_POINT`` (set to 31.4 by default as the AB definition is zp=8.9 for 1 Jy) and the standard AB magnitude relation. :param mag: AB magnitude value(s). :type mag: float or numpy.ndarray :returns: Flux density value(s) in nJy. :rtype: float or numpy.ndarray .. py:function:: flux2mag(flux_njy: float | numpy.ndarray) -> float | numpy.ndarray Convert flux density in nanoJanskys (nJy) to AB magnitude(s). This uses the module-level ``ZERO_POINT`` (set to 31.4 by default as the AB definition is zp=8.9 for 1 Jy) and the inverse AB relation. Note that to avoid log of zero or negative flux issues, flux values are clipped to a minimum of ``1e-10`` nJy prior to conversion. :param flux_njy: Flux density value(s) in nJy. :type flux_njy: float or numpy.ndarray :returns: AB magnitude value(s). :rtype: float or numpy.ndarray .. py:function:: abmag_to_njy(mag: float | numpy.ndarray) -> float | numpy.ndarray Convert AB magnitude(s) to flux density in nanoJanskys (nJy) using pyLIMA. This calls ``pyLIMA.toolbox.brightness_transformation.magnitude_to_flux``. Note that in this pipeline, the pyLIMA brightness transformation module is configured at import time by overwriting its module-level ``ZERO_POINT`` and ``EXPOSURE_TIME`` so the conversion is always in the same calibrated physical units. :param mag: AB magnitude value(s). :type mag: float or numpy.ndarray :returns: Flux density value(s) in nJy. :rtype: float or numpy.ndarray .. py:function:: njy_to_abmag(flux_njy: float | numpy.ndarray) -> float | numpy.ndarray Convert flux density in nanoJanskys (nJy) to AB magnitude(s) using pyLIMA. This calls ``pyLIMA.toolbox.brightness_transformation.flux_to_magnitude``. In this pipeline, the pyLIMA brightness transformation module is configured at import time by overwriting its module-level ``ZERO_POINT`` and ``EXPOSURE_TIME`` so the conversion is always in the same calibrated physical units. :param flux_njy: Flux density value(s) in nJy. :type flux_njy: float or numpy.ndarray :returns: AB magnitude value(s). :rtype: float or numpy.ndarray .. py:function:: t_m_boundaries(event=None, model=None) Return parameter bounds for the extended-lens timescale parameter ``t_m``. This function is assigned to ``pyLIMA.priors.parameters_boundaries.t_m_boundaries`` for pyLIMA compatability, and is used only when sampling/validating the extended dark object models. :param event: Placeholder argument for pyLIMA API compatibility. Not used. :type event: object, optional :param model: Placeholder argument for pyLIMA API compatibility. Not used. :type model: object, optional :returns: Lower and upper bounds for ``t_m`` in days: ``[0.1, 10.0]``. :rtype: list of float .. py:class:: ModelSpec Container specifying parameter requirements for a microlensing model. This dataclass describes which entries are required/optional in the user-facing ``model_params`` dictionary for each supported model type. It also supports alias mapping (to accommodate alternate naming conventions, just in case) and defaults for optional parameters. .. attribute:: required Names of required keys that must be present in ``model_params`` for this model. :type: tuple of str .. attribute:: optional Names of optional keys allowed in ``model_params`` for this model. :type: tuple of str .. attribute:: defaults Default values injected into ``model_params`` when missing. Only applies to keys listed in ``optional`` (or otherwise expected by the model wrapper). :type: dict of str to Any .. attribute:: aliases Mapping from alias key -> canonical key. If an alias is provided and the canonical key is missing, the alias value is copied to the canonical key. Intended to tolerate common synonyms and/or upstream naming changes. :type: dict of str to str .. attribute:: notes Human-readable description of the model and any important usage notes. :type: str .. attribute:: example Example ``model_params`` dictionary illustrating typical usage. :type: dict of str to Any .. py:attribute:: required :type: tuple[str, Ellipsis] .. py:attribute:: optional :type: tuple[str, Ellipsis] .. py:attribute:: defaults :type: dict[str, Any] .. py:attribute:: aliases :type: dict[str, str] .. py:attribute:: notes :type: str .. py:attribute:: example :type: dict[str, Any] .. py:data:: MODEL_SPECS :type: dict[str, ModelSpec] .. py:function:: describe_model_requirements(model_type: str) -> str Return a human-readable description of parameter requirements for a model. This helper summarizes the required and optional ``model_params`` keys for the requested model type, and includes any defaults, aliases, notes, and an example (when available). It is primarily used to generate informative error messages. :param model_type: Model identifier (must match a key in ``MODEL_SPECS``). :type model_type: str :returns: Multi-line description of the model's requirements. If ``model_type`` is not supported, returns a message listing the allowed model types. :rtype: str .. py:function:: _normalize_model_type(model_type: str) -> str Normalize a user-supplied model type string to its identifier. Normalization is case-insensitive and trims whitespace. A small set of common variants are mapped to supported canonical names (e.g., ``"FSPLarge"`` -> ``"FSPL"``). :param model_type: User-provided model type string. :type model_type: str :returns: Canonical model type string used for lookups in ``MODEL_SPECS``. :rtype: str .. py:function:: normalize_model_params(model_type: str, model_params: dict | None) -> dict[str, Any] Normalize a ``model_params`` dictionary for a given model type. This function applies alias mappings (e.g., ``sep`` -> ``s``) when canonical keys are absent and removes alias keys when both alias and canonical are present (to avoid duplicates). It also injects default values for missing optional parameters defined in ``MODEL_SPECS``. :param model_type: Model identifier (case-insensitive). Normalized via ``_normalize_model_type``. :type model_type: str :param model_params: User-supplied model parameters. If None, an empty dictionary is assumed. :type model_params: dict or None :returns: A new dictionary containing normalized model parameters. :rtype: dict of str to Any .. py:function:: validate_model_params(model_type: str, model_params: dict[str, Any] | None) -> dict[str, Any] Validate and normalize model-specific parameters. This enforces (1) required keys for the requested model, and (2) rejection of unknown keys to catch typos early. It also applies alias mappings and default values via :func:`normalize_model_params`. :param model_type: Model identifier (case-insensitive). Normalized via ``_normalize_model_type``. :type model_type: str :param model_params: User-supplied model parameters. If None, an empty dictionary is assumed. :type model_params: dict of str to Any or None :returns: Normalized ``model_params`` dictionary with aliases applied and defaults injected (when defined in ``MODEL_SPECS``). :rtype: dict of str to Any .. py:function:: validate_parallax(parallax_params: dict | None) -> dict | None Validate and normalize parallax parameters for pyLIMA. Parallax is represented by the North/East components of the microlensing parallax vector: ``piEN`` and ``piEE``. :param parallax_params: Parallax parameter dictionary. If provided, it must contain both keys ``"piEN"`` and ``"piEE"``. If None, parallax is treated as disabled. :type parallax_params: dict or None :returns: If ``parallax_params`` is None, returns None. Otherwise returns a new dict ``{"piEN": float(...), "piEE": float(...)}``. :rtype: dict or None .. py:function:: validate_photometry(*, bands: tuple[str, Ellipsis], source_mags: dict[str, float] | None, blend_mags: dict[str, float] | None, blend_g: dict[str, float] | float | None) -> None Validate photometric inputs for simulated multi-band light curves. This checks that ``source_mags`` is a non-empty dict and provides an AB magnitude for every requested band in ``bands``. It also checks that blending is specified in exactly one way, either ``blend_mags`` (explicit blend magnitudes per band) or ``blend_g`` (blend-to-source flux ratio), but not both. Also, if ``blend_mags`` is provided, it includes all requested bands, and if ``blend_g`` is a dict, it includes all requested bands (a single scalar is allowed and applies to all bands). :param bands: Photometric band names that will be simulated (e.g., ``("g", "r", "i")``). :type bands: tuple of str :param source_mags: Source AB magnitudes per band. Must include every band in ``bands``. :type source_mags: dict of str to float or None :param blend_mags: Blend-only AB magnitudes per band. If provided, must include every band in ``bands``. Mutually exclusive with ``blend_g``. :type blend_mags: dict of str to float or None :param blend_g: Blend-to-source flux ratio ``g = f_blend / f_source``. May be a scalar applied to all bands or a per-band dictionary. Mutually exclusive with ``blend_mags``. :type blend_g: dict of str to float, float, or None :returns: This function returns None if validation passes. :rtype: None .. py:data:: m_nfw_inner :value: None .. py:data:: dm_nfw_inner :value: None .. py:data:: m_boson_inner :value: None .. py:data:: dm_boson_inner :value: None .. py:data:: NFW_LOADED :value: False .. py:data:: BS_LOADED :value: False .. py:data:: _NFW_TABLE :value: 'mt_nfw_list.csv' .. py:data:: _BS_TABLE :value: 'mt_boson_list.csv' .. py:function:: load_and_interpolate_mass_function(csv_path_or_name: str | None = None, drop_row: int | None = None, base_dir: str | None = None) Load a 1D extended-lens mass-function table and build spline interpolants. The input CSV is expected to contain two columns with no header -- a column 0: ``t`` (dimensionless coordinate; may be stored as strings that can be evaluated to floats), and a column 1: ``mt`` (dimensionless enclosed-mass function evaluated at ``t``) For numerical stability and symmetry, the table is mirrored to negative ``t`` by reversing the original arrays and negating ``t``. Optionally, one row in the mirrored half may be dropped (useful when the original table includes an endpoint that would be duplicated by the mirroring). If ``drop_row`` is None, a point ``(t=0, mt=0)`` is appended to the mirrored half before concatenation. The function returns a cubic B-spline interpolant ``m_inner(t)`` and its derivative ``dm_inner(t)`` as callable objects suitable for the extended-lens magnification calculation. :param csv_path_or_name: Path to the CSV file, or a filename to be joined with ``base_dir``. This file is saved in the package's data directory and will be loaded when this is None! This should really never be set by the user... :type csv_path_or_name: str :param drop_row: If provided, drops this row index from the mirrored (negative-``t``) half before concatenation. If None, appends ``(0, 0)`` to the mirrored half instead. Default is None. :type drop_row: int or None, optional :param base_dir: If provided and ``csv_path_or_name`` is a relative path, the file path is constructed as ``os.path.join(base_dir, csv_path_or_name)``. Default is None. This should really never be set by the user... :type base_dir: str or None, optional :returns: ``(m_inner, dm_inner)``, where both entries are callable spline objects. If loading or interpolation fails, returns ``(None, None)``. :rtype: tuple .. py:function:: load_custom_extended_lens_tables(nfw_csv_path: str | None = None, boson_csv_path: str | None = None, *, nfw_drop_row: int = 0, base_dir: str | None = None) -> None Load and cache mass-function spline tables for extended-lens models (NFW / BS). NOTE: The csv_path_or_name and base_dir SHOULD JUST BE NONE ALWAYS! End user should not be updating this table manually (unless it's our team with an updated file!) :param nfw_csv_path: Path (or filename) to the NFW mass-function CSV. If None, the NFW tables are not loaded/modified. :type nfw_csv_path: str or None :param boson_csv_path: Path (or filename) to the boson-star (BS) mass-function CSV. If None, the BS tables are not loaded/modified. :type boson_csv_path: str or None :param nfw_drop_row: Row index to drop from the mirrored half of the NFW table before concatenation. Default is 0 (matching the original pipeline behavior). :type nfw_drop_row: int, optional :param base_dir: Base directory prepended to relative paths for both CSV inputs. Default is None. :type base_dir: str or None, optional :returns: This function returns None, it only updates module-level spline objects and flags. :rtype: None .. py:function:: calculate_magnification(tau, beta, t_m, m, dm) Compute photometric magnification for an extended lens via root finding. This routine evaluates the magnification for an extended (non-point) lens model by solving a 1D lens equation for each impact parameter ``u(t)``. For each time sample, the method first computes the instantaneous impact parameter ``u_t`` from the source trajectory coordinates (``tau``, ``beta``). It then finds all real roots of the extended-lens lens equation (image positions) on a fixed 1D scan interval by detecting sign changes and refining each root with ``scipy.optimize.root_scalar``. It then computes the signed magnification contribution for each image using the Jacobian factors that depend on the enclosed-mass function ``m(t, t_m)`` and its derivative ``dm(t, t_m)``. The total magnification that is returned is then the sum of absolute image magnifications. :param tau: Dimensionless trajectory coordinate along the direction of motion (as returned by pyLIMA's trajectory builder). :type tau: array-like :param beta: Dimensionless trajectory coordinate perpendicular to the direction of motion. :type beta: array-like :param t_m: Extended-lens characteristic scale. :type t_m: float :param m: Enclosed-mass function for the model. Must accept ``(t, t_m)`` and return ``m(t, t_m)`` evaluated elementwise for array-like ``t``. :type m: callable :param dm: Derivative of the enclosed-mass function with respect to ``t``. Must accept ``(t, t_m)`` and return ``dm(t, t_m)`` evaluated elementwise for array-like ``t``. :type dm: callable :returns: Array of magnifications with the same length as the computed impact-parameter array. If no roots are found for a given time sample, the magnification is set to 1.0 (i.e., no lensing). :rtype: numpy.ndarray .. py:function:: m_nfw(t, t_m) Evaluate the dimensionless enclosed-mass function for the NFW extended lens. :param t: Image-plane coordinate(s) at which to evaluate the mass function. :type t: float or numpy.ndarray :param t_m: Extended-lens scale parameter defining the truncation boundary. :type t_m: float :returns: Enclosed-mass function value(s) ``m(t, t_m)``. The return type matches the shape of ``t``. :rtype: float or numpy.ndarray .. py:function:: dm_nfw(t, t_m) Evaluate the derivative of the NFW enclosed-mass function with respect to ``t``. :param t: Image-plane coordinate(s) at which to evaluate the derivative. :type t: float or numpy.ndarray :param t_m: Extended-lens scale parameter defining the truncation boundary. :type t_m: float :returns: Derivative value(s) ``dm(t, t_m)``. The return type matches the shape of ``t``. :rtype: float or numpy.ndarray .. py:function:: m_boson(t, t_m) Evaluate the dimensionless enclosed-mass function for the boson-star (BS) extended lens. :param t: Image-plane coordinate(s) at which to evaluate the mass function. :type t: float or numpy.ndarray :param t_m: Extended-lens scale parameter defining the truncation boundary. :type t_m: float :returns: Enclosed-mass function value(s) ``m(t, t_m)``. The return type matches the shape of ``t``. :rtype: float or numpy.ndarray .. py:function:: dm_boson(t, t_m) Evaluate the derivative of the boson-star (BS) enclosed-mass function with respect to ``t``. :param t: Image-plane coordinate(s) at which to evaluate the derivative. :type t: float or numpy.ndarray :param t_m: Extended-lens scale parameter defining the truncation boundary. :type t_m: float :returns: Derivative value(s) ``dm(t, t_m)``. The return type matches the shape of ``t``. :rtype: float or numpy.ndarray .. py:class:: ExtendedLensModel Bases: :py:obj:`pyLIMA.models.PSPL_model.PSPLmodel` Base class for extended-lens photometric microlensing models in pyLIMA. This class subclasses pyLIMA's ``PSPLmodel`` but replaces the point-lens magnification with an extended-lens magnification computed from a model-specific enclosed-mass function ``m(t, t_m)`` and its derivative ``dm(t, t_m)``. Subclasses must provide a ``model_mass_functions`` property returning the pair ``(m, dm)`` callables used by :func:`calculate_magnification`. In this pipeline, concrete subclasses include ``NFWmodel`` and ``BSmodel``. .. py:method:: paczynski_model_parameters() Define the ordered set of core photometric parameters for the extended lens. This extends the standard Paczyński parameterization by including the additional extended-lens scale parameter ``t_m``. The returned mapping is used to build pyLIMA's internal parameter dictionary ordering. :returns: Mapping from parameter name to index in the ordered pyLIMA parameter vector. The base ordering is: ``{"t0": 0, "u0": 1, "tE": 2, "t_m": 3}``. :rtype: dict of str to int .. py:method:: define_pyLIMA_standard_parameters() Construct pyLIMA's standard parameter dictionary for this extended-lens model. This method builds the full parameter set expected by pyLIMA by starting from the extended Paczyński parameters (``t0``, ``u0``, ``tE``, ``t_m``) and then adding any relevant astrometric, second-order, and per-telescope flux parameters using pyLIMA helper methods. The resulting dictionary is stored in ``self.pyLIMA_standards_dictionnary`` as an ``OrderedDict`` sorted by the assigned parameter indices. The parameter boundaries are set to ``(0, +inf)`` for all parameters as default. :returns: This method updates instance attributes used internally by pyLIMA. :rtype: None .. py:method:: model_magnification(telescope, pyLIMA_parameters, return_impact_parameter=False) Compute the photometric magnification for an extended lens at telescope epochs. The source trajectory is computed using pyLIMA's trajectory machinery and then passed to :func:`calculate_magnification`, along with the extended-lens scale parameter ``t_m`` and the model-specific mass-function callables. :param telescope: pyLIMA telescope object containing timestamps and (after simulation) a ``lightcurve`` attribute. :type telescope: object :param pyLIMA_parameters: pyLIMA parameter container/dictionary with at least the key ``"t_m"``, along with the usual microlensing parameters needed to compute the trajectory. :type pyLIMA_parameters: dict-like :param return_impact_parameter: Included for API compatibility with pyLIMA. This implementation ignores the flag and always returns the magnification array. :type return_impact_parameter: bool, optional :returns: Array of magnifications evaluated at the telescope timestamps. If the telescope has no lightcurve attached (``telescope.lightcurve is None``), returns None. :rtype: numpy.ndarray or None .. py:class:: NFWmodel Bases: :py:obj:`ExtendedLensModel` Extended-lens microlensing model using an NFW-like enclosed-mass profile. .. py:property:: model_mass_functions Return the enclosed-mass function and its derivative for the NFW model. :returns: ``(m_nfw, dm_nfw)``, callables with signature ``(t, t_m)``. :rtype: tuple of callable .. py:property:: _model_type Return the model type label used internally by this pipeline. :returns: Model type string: ``"NFW"``. :rtype: str .. py:class:: BSmodel Bases: :py:obj:`ExtendedLensModel` Extended-lens microlensing model using a boson-star enclosed-mass profile. .. py:property:: model_mass_functions Return the enclosed-mass function and its derivative for the BS model. :returns: ``(m_boson, dm_boson)``, callables with signature ``(t, t_m)``. :rtype: tuple of callable .. py:property:: _model_type Return the model type label used internally by this pipeline. :returns: Model type string: ``"BS"``. :rtype: str .. py:function:: build_time_grid_jd(*, t0_mjd: float, tE_days: float, window_size_days: float = 4000.0, peak_width_factor: float = 5.0, step_dense_days: float = 0.1, step_sparse_days: float = 10.0) -> numpy.ndarray Construct an adaptive Julian Date (JD) time grid centered on a microlensing event. The grid is sampled densely near the event peak and sparsely in the wings, with a dense "core" region (``t0 plus/minus (peak_width_factor * tE)``, sampled every ``step_dense_days``) and sparse wings (outside the core region out to ``t0 plus/minus window_size_days``, sampled every ``step_sparse_days``). This is primarily used when the user does not provide an explicit cadence and wants a "perfect" (noise-free) model. :param t0_mjd: Event time of maximum magnification in Modified Julian Date (MJD). :type t0_mjd: float :param tE_days: Einstein timescale ``tE`` in days. :type tE_days: float :param window_size_days: Half-width of the full time window around ``t0`` (in days). The grid spans ``[t0 - window_size_days, t0 + window_size_days]`` in JD. Default is 4000.0. :type window_size_days: float, optional :param peak_width_factor: Sets the half-width of the densely sampled core as ``peak_width_factor * tE_days``. Default is 5.0. :type peak_width_factor: float, optional :param step_dense_days: Step size (days) in the densely sampled core region. Default is 0.1. :type step_dense_days: float, optional :param step_sparse_days: Step size (days) in the sparsely sampled wings. Default is 10.0. :type step_sparse_days: float, optional :returns: 1D array of timestamps in Julian Date (JD), sorted in ascending order. :rtype: numpy.ndarray .. py:function:: _compute_fsource_fblend_for_band(*, band: str, source_mag: float, blend_mags: dict[str, float] | None, blend_g: dict[str, float] | float | None) -> tuple[float, float] Compute per-band source and blend fluxes (nJy) from magnitude-based inputs. This helper converts the photometric inputs for a single band into the ``(fsource, fblend)`` values expected by pyLIMA. It supports two mutually exclusive blending conventions: 1. ``blend_mags`` (physical blending): - ``source_mag`` is the source-only AB magnitude in this band. - ``blend_mags[band]`` is the blend-only AB magnitude in this band. 2. ``blend_g`` (blend ratio method): - ``source_mag`` is the total baseline AB magnitude in this band (source + blend). - ``blend_g`` defines the flux ratio ``g = f_blend / f_source`` (either a scalar applied to all bands or a per-band dict). If neither blending input is provided, the blend flux is set to 0 and the source flux is computed directly from ``source_mag``. :param band: Band label (e.g., ``"g"``, ``"r"``, ``"i"``). Used to index ``blend_mags`` or dict-style ``blend_g`` when provided. :type band: str :param source_mag: AB magnitude in the specified band. Interpretation depends on blending mode: source-only if ``blend_mags`` is provided, otherwise total baseline if ``blend_g`` is provided, otherwise source-only with no blend. :type source_mag: float :param blend_mags: Blend-only AB magnitudes per band. If provided, must contain ``band``. :type blend_mags: dict of str to float or None :param blend_g: Blend-to-source flux ratio ``g = f_blend / f_source``. May be a scalar or per-band dictionary. If a dict is provided, it must contain ``band``. :type blend_g: dict of str to float, float, or None :returns: ``(fsource_njy, fblend_njy)`` in nJy. :rtype: tuple of float .. py:function:: simulate_perfect_event(*, model_type: str, ra: float, dec: float, t0_mjd: float, u0: float, tE: float, bands: tuple[str, Ellipsis] = ('u', 'g', 'r', 'i', 'z', 'y'), time_grid_jd: numpy.ndarray | None = None, model_params: dict | None = None, parallax_params: dict | None = None, source_mags: dict[str, float] | None = None, blend_mags: dict[str, float] | None = None, blend_g: dict[str, float] | float | None = None) -> dict[str, pandas.DataFrame] Simulate a noise-free ("perfect") multi-band microlensing light curve with pyLIMA. This function constructs a pyLIMA ``Event`` with one simulated telescope per band, evaluates the selected microlensing model on a user-specified (or automatically generated) time grid, and returns per-band light curves in both magnitude and flux (nJy). No observational noise is added; the intent is for downstream code to resample to a survey cadence and inject noise separately. :param model_type: Microlensing model identifier. Supported values are the keys of ``MODEL_SPECS`` (e.g., ``"PSPL"``, ``"FSPL"``, ``"USBL"``, ``"NFW"``, ``"BS"``). The value is normalized via ``_normalize_model_type``. :type model_type: str :param ra: Right ascension of the event in degrees. :type ra: float :param dec: Declination of the event in degrees. :type dec: float :param t0_mjd: Time of maximum magnification in Modified Julian Date (MJD). :type t0_mjd: float :param u0: Impact parameter at closest approach (dimensionless). :type u0: float :param tE: Einstein timescale in days. :type tE: float :param bands: Photometric bands to simulate. One pyLIMA telescope is created per band. Default is ``("u", "g", "r", "i", "z", "y")``. :type bands: tuple of str, optional :param time_grid_jd: Array of timestamps in Julian Date (JD). If None, an adaptive grid is generated with :func:`build_time_grid_jd`. Default is None. :type time_grid_jd: numpy.ndarray or None, optional :param model_params: Model-specific parameters. Requirements depend on ``model_type`` and are enforced by :func:`validate_model_params`. Examples: - FSPL: ``{"rho": 1e-3}`` - USBL: ``{"s": 1.15, "q": 1e-3, "rho": 1e-3, "alpha": 0.4, "origin": "center_of_mass"}`` - NFW/BS: ``{"t_m": 3.0}`` :type model_params: dict or None, optional :param parallax_params: Parallax parameters ``{"piEN": ..., "piEE": ...}``. If None, parallax is disabled. Validated by :func:`validate_parallax`. :type parallax_params: dict or None, optional :param source_mags: Source magnitudes per band in AB mag. Must include all requested ``bands``. Interpretation depends on blending mode (see ``blend_mags`` / ``blend_g``). :type source_mags: dict of str to float or None, optional :param blend_mags: Blend-only magnitudes per band in AB mag (physical blending). If provided, must include all requested ``bands``. Mutually exclusive with ``blend_g``. :type blend_mags: dict of str to float or None, optional :param blend_g: Blend ratio method with ``g = f_blend / f_source``. May be a scalar applied to all bands or a per-band dict. If provided, ``source_mags`` are interpreted as total baseline magnitudes (source + blend). Mutually exclusive with ``blend_mags``. :type blend_g: dict of str to float, float, or None, optional :returns: Mapping ``band -> lightcurve``. Each DataFrame contains columns: - ``mjd``: timestamps in MJD - ``flux_njy``: flux density in nJy (derived from model magnitudes) - ``mag``: AB magnitudes from pyLIMA Rows are sorted by ``mjd`` within each band. :rtype: dict of str to pandas.DataFrame .. py:function:: write_lightcurves_txt(lightcurves: dict[str, pandas.DataFrame], output_file: str, *, meta: dict | None = None) -> None Write multi-band light curves to a single tab-delimited text file. :param lightcurves: Mapping ``band -> DataFrame``. Each DataFrame must contain the columns ``"mjd"``, ``"mag"``, and ``"flux_njy"``. :type lightcurves: dict of str to pandas.DataFrame :param output_file: Path to the output text file. :type output_file: str :param meta: Optional metadata to include as comment lines at the top of the file. Default is None. :type meta: dict or None, optional :returns: This function writes a file and returns None. :rtype: None .. py:function:: plot_lightcurves_mag(lightcurves: dict[str, pandas.DataFrame], *, title: str | None = None, invert_mag: bool = True) Plot multi-band light curves in AB magnitudes versus MJD. :param lightcurves: Mapping ``band -> DataFrame``. Each DataFrame must contain the columns ``"mjd"`` and ``"mag"``. :type lightcurves: dict of str to pandas.DataFrame :param title: Optional plot title. Default is None. :type title: str or None, optional :param invert_mag: If True, invert the y-axis so smaller magnitudes plot higher. Default is True. :type invert_mag: bool, optional :returns: Displays a Matplotlib figure and returns None. :rtype: None