Skip to content

Make laser parameters configurable; utility function for tunable laser - #970

Draft
oczoske wants to merge 1 commit into
mainfrom
oc/metis_lasers
Draft

Make laser parameters configurable; utility function for tunable laser#970
oczoske wants to merge 1 commit into
mainfrom
oc/metis_lasers

Conversation

@oczoske

@oczoske oczoske commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

The laser parameters (wavelength, power) are now taken from wcu.meta, i.e. from a config file or from kwargs.
All parameters can be changed by doing, e.g.

wcu = metis['wcu_source']
wcu.meta['laser_l_wave'] = 3.15
wcu.set_lamp("laser")

set_lamp is necessary to recompute the lamp emission.

The wavelengths of the tunable laser should be more easily accessible to the user, therefore a utility method is offered (this recomputes the emission automatically):

wcu.tune_laser(wavelength=np.linspace(4.68, 4.78, 10))

A validation method for the wavelengths has been implemented but is not yet used as we do not have reliable information on the actually available wavelength range.

@oczoske oczoske self-assigned this Aug 11, 2026
@oczoske oczoske added API How users interact with the software instrument-specific METIS AIT Issues relating to METIS AIT simulations labels Aug 11, 2026
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.32258% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.92%. Comparing base (5b85425) to head (b7f5db6).

Files with missing lines Patch % Lines
scopesim/effects/metis_wcu/metis_wcu.py 90.32% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #970      +/-   ##
==========================================
+ Coverage   75.89%   75.92%   +0.03%     
==========================================
  Files          70       70              
  Lines        9030     9054      +24     
==========================================
+ Hits         6853     6874      +21     
- Misses       2177     2180       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@teutoburg teutoburg moved this to 👀 Awaiting Review in ScopeSim-development Aug 12, 2026

@teutoburg teutoburg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See individual comments, but overall fine.

Comment on lines +214 to +215
if not hasattr(wavelength, "__len__"):
wavelength = [wavelength]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you want instead of these hasattr checks is either isinstance(wavelength, Iterable) (from collections.abc import Iterable), or, to do it entirely in one line, wavelength = always_iterable(wavelength) (from more_itertools import always_iterable). Both variants are fine for me.

Comment on lines +228 to +245
def _validate_tunable(self, wave):
"""Validate wave against a wavelength range

This is currently not used as there is no reliable
information on the tuning range of the QCL.
"""
reject = []
accept = []
lam_min = 1.
lam_max = 30.
for lam in wave:
if lam < lam_min or lam > lam_max:
reject.append(lam)
else:
accept.append(lam)
if len(reject) > 0:
logger.warning("Removed %d wavelengths outside allowed range (%f, %f) um", len(reject), lam_min, lam_max)
return accept

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function could be done more elegantly with numpy, instead of that loop. Something like

mask = (lam_min < wave) & (wave < lam_max)
n_rejected = len(wave) - mask.sum()
# warning ...
return wave[mask]

Also, I think this needs to either put the lam_min and lam_max into the arguments, or take the values from self.. The currently used defaults could then be stored either in self or as default values for the arguments. If you go with arguments, you can even decorate this with a @staticmethod, because self isn't used anywhere.

print("Computing laser intensity")
logger.info("Computing laser intensity")
lam = self.wavelength
dlam = lam[1] - lam[0]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to check if lam is evenly spaced? Your current dlam silently assumes that I think.

Comment on lines +481 to +482
if not hasattr(self.meta['laser_t_wave'], "__len__"):
self.meta['laser_t_wave'] = [self.meta['laser_t_wave']]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

intens_2 = np.sum(bbsource.intens_lamp)

assert intens_2 / intens_1 == ft_2 / ft_1
assert np.allclose(intens_2 / intens_1, ft_2 / ft_1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert np.allclose(intens_2 / intens_1, ft_2 / ft_1)
npt.assert_allclose(intens_2 / intens_1, ft_2 / ft_1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API How users interact with the software instrument-specific METIS AIT Issues relating to METIS AIT simulations

Projects

Status: 👀 Awaiting Review

Development

Successfully merging this pull request may close these issues.

2 participants