diff --git a/scopesim/effects/effects.py b/scopesim/effects/effects.py index eeb48f4b..d4280512 100644 --- a/scopesim/effects/effects.py +++ b/scopesim/effects/effects.py @@ -22,7 +22,7 @@ class Effect(DataContainer): Essentially, a sub-classed Effects object must only contain the following attributes: - * ``self.meta`` - a dictionary to contain meta data. + * ``self.meta`` - a dictionary to contain metadata. * ``self.apply_to(obj, **kwargs)`` - a method which accepts a Source-derivative and returns an instance of the same class as ``obj`` * ``self.fov_grid(which="", **kwargs)`` @@ -34,7 +34,7 @@ class Effect(DataContainer): """ - def __init__(self, cmds=None, **kwargs): + def __init__(self, **kwargs): super().__init__(**kwargs) self.meta["z_order"] = [] self.meta["include"] = True @@ -112,7 +112,8 @@ def display_name(self): name = self.meta.get("name", self.meta.get("filename", "")) if not hasattr(self, "_current_str"): return name - return f"{name} : [{from_currsys(self.meta[self._current_str], self.cmds)}]" + current_str = from_currsys(self.meta[self._current_str], self.cmds) + return f"{name} : [{current_str}]" @property def meta_string(self): diff --git a/scopesim/effects/fits_headers.py b/scopesim/effects/fits_headers.py index ced8b1ce..7fbd37ab 100644 --- a/scopesim/effects/fits_headers.py +++ b/scopesim/effects/fits_headers.py @@ -220,7 +220,7 @@ class ExtraFitsKeywords(Effect): def __init__(self, cmds=None, **kwargs): # don't pass kwargs, as DataContainer can't handle yaml files - super().__init__() + super().__init__(cmds=cmds) params = {"name": "extra_fits_keywords", "description": "Extra FITS headers", "z_order": [999], @@ -308,8 +308,8 @@ def get_relevant_extensions(dic, hdul): return exts -def flatten_dict(dic, base_key="", flat_dict=None, - resolve=False, optics_manager=None): +def flatten_dict(dic, base_key="", flat_dict=None, resolve=False, + optics_manager=None, cmds=None): """ Flattens nested yaml dictionaries into a single level dictionary. @@ -323,18 +323,23 @@ def flatten_dict(dic, base_key="", flat_dict=None, If True, resolves !-str via from_currsys and #-str via optics_manager optics_manager : scopesim.OpticsManager Required for resolving #-strings + cmds : UserCommands + To use for resolving !-strings Returns ------- flat_dict : dict """ + if cmds is None and optics_manager is not None: + cmds = optics_manager.cmds + if flat_dict is None: flat_dict = {} for key, val in dic.items(): flat_key = f"{base_key}{key} " if isinstance(val, dict): - flatten_dict(val, flat_key, flat_dict, resolve, optics_manager) + flatten_dict(val, flat_key, flat_dict, resolve, optics_manager, cmds) else: flat_key = flat_key[:-1] @@ -349,7 +354,7 @@ def flatten_dict(dic, base_key="", flat_dict=None, # resolve any bang or hash strings if resolve and isinstance(value, str): if value.startswith("!"): - value = from_currsys(value) + value = from_currsys(value, cmds) elif value.startswith("#"): if optics_manager is None: raise ValueError("An OpticsManager object must be " diff --git a/scopesim/effects/metis_lms_trace_list.py b/scopesim/effects/metis_lms_trace_list.py index ada22bb4..6872038f 100644 --- a/scopesim/effects/metis_lms_trace_list.py +++ b/scopesim/effects/metis_lms_trace_list.py @@ -198,7 +198,7 @@ def rectify_cube(self, hdulist, xi_min=None, xi_max=None, interps=None, interps = make_image_interpolations(inhdul, kx=1, ky=1) # Create a common wcs for the rectification - dwave = from_currsys("!SIM.spectral.spectral_bin_width") + dwave = from_currsys("!SIM.spectral.spectral_bin_width", self.cmds) xi_min = np.min(self.slicelist["left"]) xi_max = np.max(self.slicelist["right"]) wave_min = self.meta["wave_min"] @@ -231,8 +231,8 @@ def rectify_cube(self, hdulist, xi_min=None, xi_max=None, interps=None, # FIXME: use wcs object here cubehdr = fits.Header() - cubehdr["INSMODE"] = from_currsys(self.meta["element_name"]) - cubehdr["WAVELEN"] = from_currsys(self.meta["wavelen"]) + cubehdr["INSMODE"] = from_currsys(self.meta["element_name"], self.cmds) + cubehdr["WAVELEN"] = from_currsys(self.meta["wavelen"], self.cmds) cubehdr["CTYPE1"] = "LINEAR" cubehdr["CTYPE2"] = "LINEAR" cubehdr["CTYPE3"] = "WAVE" @@ -254,7 +254,7 @@ def rectify_cube(self, hdulist, xi_min=None, xi_max=None, interps=None, def _angle_from_lambda(self): """Determine optimal echelle rotation angle for wavelength.""" - lam = from_currsys(self.meta["wavelen"]) + lam = from_currsys(self.meta["wavelen"], self.cmds) grat_spacing = self.meta["grat_spacing"] wcal = self._file["WCAL"].data return echelle_setting(lam, grat_spacing, wcal) @@ -332,7 +332,7 @@ def get_waverange(self, det_mm_lims): xmin = det_mm_lims["xd_min"] xmax = det_mm_lims["xd_max"] - lam0 = from_currsys(self.meta["wavelen"]) + lam0 = from_currsys(self.meta["wavelen"], self.cmds) xi0 = 0. ymid = self.xilam2y(xi0, lam0)[0] # estimate y level of trace waverange = self.xy2lam(np.array([xmin, xmax]), np.array([ymid, ymid]), @@ -459,7 +459,7 @@ def __repr__(self): def __str__(self): msg = (f" \"{self.meta['description']}\" : " - f"{from_currsys(self.meta['wavelen'])} um : " + f"{from_currsys(self.meta['wavelen'], self.cmds)} um : " f"Order {self.meta['order']} : Angle {self.meta['angle']}") return msg @@ -528,7 +528,7 @@ class MetisLMSImageSlicer(ApertureMask): """ def __init__(self, filename, ext_id="Aperture List", **kwargs): - filename = find_file(from_currsys(filename)) + filename = find_file(from_currsys(filename, kwargs.get("cmds"))) ap_hdr = fits.getheader(filename, extname=ext_id) ap_list = fits.getdata(filename, extname=ext_id) xmin, xmax = ap_list["left"].min(), ap_list["right"].max() @@ -567,7 +567,7 @@ def __init__(self, **kwargs): filename = find_file(self.meta["filename"]) wcal = fits.getdata(filename, extname="WCAL") if "wavelen" in kwargs: - wavelen = from_currsys(kwargs["wavelen"]) + wavelen = from_currsys(kwargs["wavelen"], kwargs.get("cmds")) grat_spacing = self.meta["grat_spacing"] ech = echelle_setting(wavelen, grat_spacing, wcal) self.meta["order"] = ech["Ord"] diff --git a/scopesim/effects/obs_strategies.py b/scopesim/effects/obs_strategies.py index 461c8469..8081bc4e 100644 --- a/scopesim/effects/obs_strategies.py +++ b/scopesim/effects/obs_strategies.py @@ -66,13 +66,13 @@ def __init__(self, **kwargs): def apply_to(self, obj, **kwargs): if isinstance(obj, DetectorBase): - chop_offsets = from_currsys(self.meta["chop_offsets"]) - nod_offsets = from_currsys(self.meta["nod_offsets"]) + chop_offsets = from_currsys(self.meta["chop_offsets"], self.cmds) + nod_offsets = from_currsys(self.meta["nod_offsets"], self.cmds) if nod_offsets is None: nod_offsets = -np.array(chop_offsets) # these offsets are in pixels, not in arcsec or mm - pixel_scale = float(from_currsys(self.meta["pixel_scale"])) + pixel_scale = float(from_currsys(self.meta["pixel_scale"], self.cmds)) chop_offsets_pixel = np.array(chop_offsets) / pixel_scale nod_offsets_pixel = np.array(nod_offsets) / pixel_scale diff --git a/scopesim/effects/rotation.py b/scopesim/effects/rotation.py index c0abc4d1..f419a335 100644 --- a/scopesim/effects/rotation.py +++ b/scopesim/effects/rotation.py @@ -35,7 +35,7 @@ def __init__(self, **kwargs): def apply_to(self, obj, **kwargs): """See parent docstring.""" if isinstance(obj, DetectorBase): - rotations = from_currsys(self.meta["rotations"]) + rotations = from_currsys(self.meta["rotations"], self.cmds) obj._hdu.data = np.rot90(obj._hdu.data, rotations) return obj diff --git a/scopesim/effects/spectral_trace_list.py b/scopesim/effects/spectral_trace_list.py index ff8c3cfe..7d8c10cb 100644 --- a/scopesim/effects/spectral_trace_list.py +++ b/scopesim/effects/spectral_trace_list.py @@ -471,8 +471,8 @@ class SpectralTraceListWheel(Effect): } _current_str = "current_trace_list" - def __init__(self, cmds=None, **kwargs): - super().__init__(cmds, **kwargs) + def __init__(self, **kwargs): + super().__init__(**kwargs) check_keys(kwargs, self.required_keys, action="error") params = { @@ -493,7 +493,6 @@ def __init__(self, cmds=None, **kwargs): fname = str(path).format(name) self.trace_lists[name] = SpectralTraceList(filename=fname, name=name, - cmds=self.cmds, **kwargs) def apply_to(self, obj, **kwargs): diff --git a/scopesim/optics/fov.py b/scopesim/optics/fov.py index a524dea5..e948f0fd 100644 --- a/scopesim/optics/fov.py +++ b/scopesim/optics/fov.py @@ -367,7 +367,7 @@ def make_image_hdu(self, use_photlam=False): [ph s-1 pixel-1] or PHOTLAM (if use_photlam=True) """ - spline_order = from_currsys("!SIM.computing.spline_order") + spline_order = from_currsys("!SIM.computing.spline_order", self.cmds) # Make waveset and canvas image fov_waveset = self.waveset @@ -393,7 +393,7 @@ def make_image_hdu(self, use_photlam=False): spline_order=spline_order) for flux, weight, x, y in self._make_image_tablefields(fluxes): - if from_currsys(self.meta["sub_pixel"]): + if from_currsys(self.meta["sub_pixel"], self.cmds): # These x and y should not be arrays when sub_pixel is # enabled, it is therefore not necessary to deploy the fix # below in the else-branch. @@ -493,7 +493,7 @@ def _make_cube_tablefields(self, specs): xpix, ypix = imp_utils.val2pix(self.header, xsky, ysky) flux_vector = specs[row["ref"]].value * row["weight"] / self.pixel_area - if from_currsys(self.meta["sub_pixel"]): + if from_currsys(self.meta["sub_pixel"], self.cmds): xs, ys, fracs = imp_utils.sub_pixel_fractions(xpix, ypix) for i, j, k in zip(xs, ys, fracs): yield flux_vector * k, i, j @@ -559,14 +559,14 @@ def make_cube_hdu(self): [ph s-1 AA-1 arcsec-2] # as needed by SpectralTrace """ - spline_order = from_currsys("!SIM.computing.spline_order") + spline_order = from_currsys("!SIM.computing.spline_order", self.cmds) # 1. Make waveset and canvas cube (area, bin_width are applied at end) # TODO: Why is this not self.waveset? What's different? - wave_unit = u.Unit(from_currsys("!SIM.spectral.wave_unit")) + wave_unit = u.Unit(from_currsys("!SIM.spectral.wave_unit"), self.cmds) fov_waveset = np.arange( self.meta["wave_min"].value, self.meta["wave_max"].value, - from_currsys("!SIM.spectral.spectral_bin_width")) * wave_unit + from_currsys("!SIM.spectral.spectral_bin_width"), self.cmds) * wave_unit fov_waveset = fov_waveset.to(u.um) # TODO: what's with this code?? @@ -613,7 +613,7 @@ def make_cube_hdu(self): # PHOTLAM = ph/s/cm-2/AA # area = m2, fov_waveset = um # SpectralTrace wants ph/s/um/arcsec2 --> get rid of m2, leave um - area = from_currsys(self.meta["area"]) # u.m2 + area = from_currsys(self.meta["area"], self.cmds) # u.m2 canvas_cube_hdu.data *= area.to(u.cm ** 2).value canvas_cube_hdu.data *= 1e4 # ph/s/AA/arcsec2 --> ph/s/um/arcsec2 diff --git a/scopesim/optics/fov_utils.py b/scopesim/optics/fov_utils.py index cf1d0431..582547f6 100644 --- a/scopesim/optics/fov_utils.py +++ b/scopesim/optics/fov_utils.py @@ -132,7 +132,7 @@ def combine_table_fields(fov_header, src, field_indexes): def combine_imagehdu_fields(fov_header, src, fields_indexes, wave_min, wave_max, - area, wcs_suffix=""): + area, wcs_suffix="", cmds=None): """ Combine list of ImageHDUs into a single one bounded by the Header WCS. @@ -161,7 +161,7 @@ def combine_imagehdu_fields(fov_header, src, fields_indexes, wave_min, wave_max, """ image = np.zeros((fov_header["NAXIS2"], fov_header["NAXIS1"])) canvas_hdu = fits.ImageHDU(header=fov_header, data=image) - spline_order = from_currsys("!SIM.computing.spline_order") + spline_order = from_currsys("!SIM.computing.spline_order", cmds) pixel_area = (fov_header["CDELT1"] * fov_header["CDELT2"] * u.Unit(fov_header["CUNIT1"].lower()).to(u.arcsec) ** 2) diff --git a/scopesim/optics/image_plane.py b/scopesim/optics/image_plane.py index 96a92464..89f34baf 100644 --- a/scopesim/optics/image_plane.py +++ b/scopesim/optics/image_plane.py @@ -45,8 +45,9 @@ class ImagePlane(ImagePlaneBase): """ - def __init__(self, header, **kwargs): + def __init__(self, header, cmds=None, **kwargs): + self.cmds = cmds max_seg_size = rc.__config__["!SIM.computing.max_segment_size"] self.meta = {"SIM_MAX_SEGMENT_SIZE": max_seg_size} self.meta.update(kwargs) @@ -109,9 +110,9 @@ def add(self, hdus_or_tables, sub_pixel=None, spline_order=None, """ if sub_pixel is None: - sub_pixel = from_currsys("!SIM.sub_pixel.flag") + sub_pixel = from_currsys("!SIM.sub_pixel.flag", self.cmds) if spline_order is None: - spline_order = from_currsys("!SIM.computing.spline_order") + spline_order = from_currsys("!SIM.computing.spline_order", self.cmds) if isinstance(hdus_or_tables, (list, tuple)): for hdu_or_table in hdus_or_tables: diff --git a/scopesim/optics/optical_train.py b/scopesim/optics/optical_train.py index 0ecb675d..769cad2f 100644 --- a/scopesim/optics/optical_train.py +++ b/scopesim/optics/optical_train.py @@ -159,7 +159,7 @@ def update(self, **kwargs): self.fov_manager = FOVManager(opt_man.fov_setup_effects, cmds=self.cmds, **kwargs) - self.image_planes = [ImagePlane(hdr, **kwargs) + self.image_planes = [ImagePlane(hdr, self.cmds, **kwargs) for hdr in opt_man.image_plane_headers] self.detector_arrays = [DetectorArray(det_list, cmds=self.cmds, **kwargs) for det_list in opt_man.detector_setup_effects]