Summary
Wire the SED component into mulensinstrument so a source star's physical parameters (teff, radius, distance, feh, av) can be constrained by the microlensing light curve's own calibrated baseline flux (f_source), not just external catalog photometry (2MASS/Gaia).
This gap is already marked in code: mulensinstrument.build_likelihood raises
NotImplementedError("SED-based f_source prior for mulensing instruments is not yet implemented.")
(src/exozippy/components/mulensing/mulensinstrument.py, ~line 550)
whenever system.sed exists. The example examples/KMT-2019-BLG-1806/ (2L1S, finite source, star.0=Lens/star.1=Source, real KMTNet I-band data) is a ready-made test case once this lands — it has no sed: block yet.
Background
- SED (
components/sed/sed.py) predicts a calibrated apparent magnitude for a star from physics via a bolometric-correction grid, and fits it against catalog mags with known zeropoints.
mulensinstrument fits f_source/f_blend per instrument as free nuisance parameters (log_f_total, q_source) in arbitrary instrumental flux units, bootstrapped via NNLS from the light curve — no physical zeropoint.
- The idea: treat the light curve's calibrated baseline photometry as one more SED data point tied to the Source star index, so
teff/radius/distance/av get informed by the survey band itself.
Process
- Index SED by star.
sed.build_likelihood/compile_plotters currently assume a single star (star.teff.value with no index). The docstring gestures at a staridx that's never implemented. Needs system.star.teff.value[staridx] etc., evaluated at the Source index (system.lens.source_map).
- Add a photometric zeropoint.
m_calibrated = -2.5*log10(f_source) + zp. New parameter, likely one per mulensinstrument entry (or shared if e.g. KMTA04/C04/S04 are already cross-calibrated — needs checking).
- Bridge filter identity. SED resolves filters from the
.sed yaml via bc_grid.resolve_filter_name (MIST/SVO aliasing). The mulensing band block only carries a bandpass string for limb darkening (e.g. "Generic/Cousins.I"). Need that name to resolve against the same BC grid, or a second BC evaluation path.
- Wire cross-component. Per the "component-specific logic stays in components" convention, expose something like
SED.predict_appmag(star_idx, filter_name); have mulensinstrument.build_likelihood call into system.sed (replacing the NotImplementedError) and add a pm.Normal/pm.Potential tying f_source (via zp) to that prediction.
- Extend
defaults.yaml in both sed/ and mulensing/ for the new zp parameter (bounds, init_scale, unit).
Open questions / risks
- zp prior is the crux. A free zp with a broad prior lets the sampler slide it to match whatever
(teff, radius, distance) the rest of the fit already prefers — the constraint becomes nearly vacuous. Needs either a fixed, user-supplied value (known field-star calibration) or an informatively-priored nuisance parameter.
- Blending degeneracy.
f_source itself comes from an NNLS split of F(t) = f_s*A(t) + f_b, well-determined only where the light curve has good non-baseline coverage. Piping a noisy f_source into the SED constraint risks propagating that degeneracy rather than reducing it. Finite-source events (measured rho, as in KMT-2019-BLG-1806) are the case where this is most likely to actually help.
- Half-built multi-star scaffolding in SED.
.sed yaml schema already has nstars/photType: {blend: [...], diff: ...} concepts in SED._process_SED_yaml for "flux is a sum of stars," but the computed photType is discarded and never reaches build_likelihood, which is single-star-scalar only. This needs finishing as part of (or before) this work, not just extending.
- Three instruments, one band. KMTA04/C04/S04 in the example are all "I" band but different sites — likely need separate zp's unless already on a common system.
Summary
Wire the SED component into
mulensinstrumentso a source star's physical parameters (teff,radius,distance,feh,av) can be constrained by the microlensing light curve's own calibrated baseline flux (f_source), not just external catalog photometry (2MASS/Gaia).This gap is already marked in code:
mulensinstrument.build_likelihoodraises(
src/exozippy/components/mulensing/mulensinstrument.py, ~line 550)whenever
system.sedexists. The exampleexamples/KMT-2019-BLG-1806/(2L1S, finite source,star.0=Lens/star.1=Source, real KMTNet I-band data) is a ready-made test case once this lands — it has nosed:block yet.Background
components/sed/sed.py) predicts a calibrated apparent magnitude for a star from physics via a bolometric-correction grid, and fits it against catalog mags with known zeropoints.mulensinstrumentfitsf_source/f_blendper instrument as free nuisance parameters (log_f_total,q_source) in arbitrary instrumental flux units, bootstrapped via NNLS from the light curve — no physical zeropoint.teff/radius/distance/avget informed by the survey band itself.Process
sed.build_likelihood/compile_plotterscurrently assume a single star (star.teff.valuewith no index). The docstring gestures at astaridxthat's never implemented. Needssystem.star.teff.value[staridx]etc., evaluated at the Source index (system.lens.source_map).m_calibrated = -2.5*log10(f_source) + zp. New parameter, likely one permulensinstrumententry (or shared if e.g. KMTA04/C04/S04 are already cross-calibrated — needs checking)..sedyaml viabc_grid.resolve_filter_name(MIST/SVO aliasing). The mulensingbandblock only carries a bandpass string for limb darkening (e.g."Generic/Cousins.I"). Need that name to resolve against the same BC grid, or a second BC evaluation path.SED.predict_appmag(star_idx, filter_name); havemulensinstrument.build_likelihoodcall intosystem.sed(replacing theNotImplementedError) and add apm.Normal/pm.Potentialtyingf_source(via zp) to that prediction.defaults.yamlin bothsed/andmulensing/for the new zp parameter (bounds,init_scale, unit).Open questions / risks
(teff, radius, distance)the rest of the fit already prefers — the constraint becomes nearly vacuous. Needs either a fixed, user-supplied value (known field-star calibration) or an informatively-priored nuisance parameter.f_sourceitself comes from an NNLS split ofF(t) = f_s*A(t) + f_b, well-determined only where the light curve has good non-baseline coverage. Piping a noisyf_sourceinto the SED constraint risks propagating that degeneracy rather than reducing it. Finite-source events (measuredrho, as in KMT-2019-BLG-1806) are the case where this is most likely to actually help..sedyaml schema already hasnstars/photType: {blend: [...], diff: ...}concepts inSED._process_SED_yamlfor "flux is a sum of stars," but the computedphotTypeis discarded and never reachesbuild_likelihood, which is single-star-scalar only. This needs finishing as part of (or before) this work, not just extending.