Models

Data models

class FileConfigModel(*, default: bool = False, id: str = '', name: str = '', description: str = '', vars: dict[str, float | str] = {}, file: str)[source]

Bases: BaseModel

Pydantic model for transmission curve configuration.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class EmissionConfigModel(*, path: str = '', temperatures: list[~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2257f0e9f0>, FieldInfo(annotation=NoneType, required=True, description='Device temperature.', json_schema_extra={'exclusiveMinimum': '0.0 K', 'physType': 'temperature'})]] = [<Quantity 283. K>], blackbody_fractions: list[~typing.Annotated[float, FieldInfo(annotation=NoneType, required=True, description='Fraction of the pupil that behaves as a pure black body.', metadata=[Ge(ge=0.0), Le(le=1.0)])]] = <factory>, files: list[~pydiet.server.models.dataconfig.FileConfigModel] = [])[source]

Bases: BaseModel

Pydantic model for emission curve set configuration.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class TransmissionConfigModel(*, path: str = '', files: list[FileConfigModel] = [])[source]

Bases: BaseModel

Pydantic model for transmission curve set configuration.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class SiteConfigModel(*, default: bool = False, id: str, name: str, description: str, path: str, altitude: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249812e70>], transmission: ~pydiet.server.models.dataconfig.TransmissionConfigModel, emission: ~pydiet.server.models.dataconfig.EmissionConfigModel)[source]

Bases: BaseModel

Pydantic model for the observing site data configuration model.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class TelescopeConfigModel(*, default: bool = False, id: str, name: str, description: str, path: str, collecting_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22497321e0>], obstruction_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22497323f0>], transmission: ~pydiet.server.models.dataconfig.TransmissionConfigModel, emission: ~pydiet.server.models.dataconfig.EmissionConfigModel)[source]

Bases: BaseModel

Pydantic model for the telescope data configuration model.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class DetectorConfigModel(*, path: str, gain: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249732630>], ron: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22497323c0>], scale: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22497326f0>], full_well: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249732cf0>], range: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249732930>], bias: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249732de0>], transmission: ~pydiet.server.models.dataconfig.TransmissionConfigModel, emission: ~pydiet.server.models.dataconfig.EmissionConfigModel)[source]

Bases: BaseModel

Detector configuration read from the instrument's TOML table.

Physical quantities must include units and are converted to the units shown below. Omitted saturation settings retain the image model's defaults.

path

Detector data directory relative to the instrument directory.

Type:

str

gain

Positive conversion factor in electrons per ADU.

Type:

Quantity

ron

Nonnegative RMS readout noise in electrons.

Type:

Quantity

scale

Two positive angular pixel scales in arcseconds per pixel.

Type:

Quantity

full_well

Positive full-well capacity in electrons; defaults to 1,000,000 electrons.

Type:

Quantity

range

Digital range in ADUs, greater than one ADU; defaults to 65,536 ADUs.

Type:

Quantity

bias

Nonnegative bias level in ADUs; defaults to zero ADUs.

Type:

Quantity

transmission

Quantum-efficiency file configuration.

Type:

TransmissionConfigModel

emission

Detector emission configuration.

Type:

EmissionConfigModel

Examples

>>> detector = DetectorConfigModel(
...     path="detector", gain="2 electron/adu", ron="4 electron",
...     scale="[0.3, 0.3] arcsec/pix", full_well="100000 electron",
...     range="65536 adu", bias="1200 adu",
...     transmission={}, emission={}
... )
>>> detector.full_well / detector.gain
<Quantity 50000. adu>
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class OpticsConfigModel(*, path: str, transmission: TransmissionConfigModel, emission: EmissionConfigModel)[source]

Bases: BaseModel

Pydantic model for the intrument optics data configuration model.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class FiltersConfigModel(*, path: str, transmission: TransmissionConfigModel, emission: EmissionConfigModel)[source]

Bases: OpticsConfigModel

Pydantic model for the intrument filters data configuration model.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class InstrumentConfigModel(*, default: bool = False, id: str, name: str, description: str, path: str, wavelength_range: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249732ff0>], obstruction_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22497330b0>, FieldInfo(annotation=NoneType, required=True, description="Instrument obstruction area; defaults to the telescope's value when omitted.", json_schema_extra={'exclusiveMinimum': '0.0 m2', 'physType': 'area'})] | None = None, overhead: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2249914470>], psf_beta: ~typing.Annotated[float, ~annotated_types.Gt(gt=1.0), ~annotated_types.Le(le=10.0)] = 3.2, site_id: str, telescope_id: str, optics: ~pydiet.server.models.dataconfig.OpticsConfigModel, filters: ~pydiet.server.models.dataconfig.FiltersConfigModel, detector: ~pydiet.server.models.dataconfig.DetectorConfigModel)[source]

Bases: BaseModel

Physical and spectral-file configuration for an imaging instrument.

site_id and telescope_id reference objects in the data configuration. If obstruction_area is omitted or None, the loader uses the referenced telescope's obstruction area. An explicit positive area overrides that default, including when it is smaller than the telescope's value.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class DataConfigModel(*, path: Annotated[Path, PathType(path_type=dir)], sites: list[SiteConfigModel], telescopes: list[TelescopeConfigModel], instruments: list[InstrumentConfigModel])[source]

Bases: BaseModel

Pydantic model for the data configuration

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Default entries for models

Exceptions for model validation.

exception ETCValidationError[source]

Bases: Exception

Report an ETC query value that is not valid for the selected instrument.

Parameters:

error (dict) -- Error details using Pydantic's type, loc, input, and context conventions.

Data models

spectral_to_arrays(spectral: BaseSpectrum) → Tuple[ndarray, ndarray][source]

Convert a spectrum to wavelength and value arrays.

One zero-valued sample is retained on either side of the non-zero region when available. An entirely zero-valued spectrum is returned unchanged.

Parameters:

spectral (synphot.spectrum.BaseSpectrum) -- Input spectrum with a defined wavelength set.

Returns:

  • wave (~numpy.ndarray) -- Wavelength samples, normally an AstroPy quantity array.

  • values (~numpy.ndarray) -- Spectrum values at wave, normally an AstroPy quantity array.

class CacheModel(*, tpeaks: dict[str, float], zp_abmags: dict[str, ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236a29b50>, FieldInfo(annotation=NoneType, required=True, description='Instrumental AB magnitude zero-point', json_schema_extra={'physType': 'unknown'})]], transmissions: dict[str, ~pydiet.server.models.instrument.TransmissionModel], emissions_ct: dict[str, float])[source]

Bases: BaseModel

Pydantic model for cached data.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class DetectorModel(*, gain: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236853aa0>], ron: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753830>], scale: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753650>], full_well: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22367533e0>], range: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753440>], bias: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753410>], transmissions: dict[str, ~pydiet.server.models.instrument.TransmissionModel], emissions: dict[str, ~pydiet.server.models.instrument.SBSEDModel])[source]

Bases: BaseModel

Physical model for an instrument detector, such as a CMOS or CCD.

gain

Positive conversion factor in electrons per ADU.

Type:

Quantity

ron

Nonnegative RMS readout noise in electrons.

Type:

Quantity

scale

Two positive angular pixel scales in arcseconds per pixel.

Type:

Quantity

full_well

Positive full-well capacity in electrons; defaults to 1,000,000 electrons.

Type:

Quantity

range

Digital range in ADUs, greater than one ADU; defaults to 65,536 ADUs.

Type:

Quantity

bias

Nonnegative bias level in ADUs; defaults to zero ADUs. Saturation calculations use the smaller of range - 1 adu - bias and full_well / gain as signal headroom.

Type:

Quantity

transmissions

Loaded quantum-efficiency curves.

Type:

dict[str, TransmissionModel]

emissions

Loaded detector emission spectra.

Type:

dict[str, SBSEDModel]

Examples

>>> detector = DetectorModel(
...     gain="2 electron/adu", ron="4 electron",
...     scale="[0.3, 0.3] arcsec/pix", full_well="100000 electron",
...     range="65536 adu", bias="1200 adu",
...     transmissions={}, emissions={}
... )
>>> detector.range - 1 * u.adu - detector.bias
<Quantity 64335. adu>
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class InstrumentModel(*, id: str, name: str, description: str, wavelength_range: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753200>], obstruction_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22367530e0>], overhead: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753170>], psf_beta: ~typing.Annotated[float, ~annotated_types.Gt(gt=1.0), ~annotated_types.Le(le=10.0)] = 3.2, filters: ~pydiet.server.models.instrument.FiltersModel, optics: ~pydiet.server.models.instrument.OpticsModel, detector: ~pydiet.server.models.instrument.DetectorModel, telescope: ~pydiet.server.models.instrument.TelescopeModel, site: ~pydiet.server.models.instrument.SiteModel, default: bool = False, cache: ~pydiet.server.models.instrument.CacheModel | None = None)[source]

Bases: BaseModel

Pydantic model for a PyDIET instrument.

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class OpticsModel(*, transmissions: dict[str, TransmissionModel], emissions: dict[str, SBSEDModel])[source]

Bases: BaseModel

Pydantic model for optics.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class FiltersModel(*, transmissions: dict[str, TransmissionModel], emissions: dict[str, SBSEDModel])[source]

Bases: OpticsModel

Pydantic model for a filter set.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class SBSEDModel(*, id: str, name: str, description: str, vars: dict[str, float | str]={}, wave: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236753080>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'maximum': '100.0 micron', 'minimum': '100.0 nm', 'physType': 'length'})] | None = None, sbsed: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236751b80>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'minimum': '0.0 Jy / arcsec2', 'physType': 'surface brightness'})] | None = None, spectral: SourceSpectrum, default: bool = False)[source]

Bases: BaseModel

Pydantic model for a Surface Brightness Spectral Energy Distribution (SBSED).

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class SEDModel(*, id: str, name: str, description: str, vars: dict[str, float]={}, wave: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236752fc0>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'maximum': '100.0 micron', 'minimum': '100.0 nm', 'physType': 'length'})] | None = None, sed: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22367517c0>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'minimum': '0.0 Jy', 'physType': 'spectral flux density'})] | None = None, spectral: SourceSpectrum, default: bool = False)[source]

Bases: BaseModel

Pydantic model for a Spectral Energy Distribution (SED).

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class SiteModel(*, id: str, name: str, description: str, sky_transmissions: dict[str, TransmissionModel], sky_emissions: dict[str, SBSEDModel], default: bool = False)[source]

Bases: BaseModel

Pydantic model for an observing site.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class TelescopeModel(*, id: str, name: str, description: str, collecting_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236cabef0>], obstruction_area: ~typing.Annotated[~astropy.units.quantity.Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236751610>], transmissions: dict[str, ~pydiet.server.models.instrument.TransmissionModel], emissions: dict[str, ~pydiet.server.models.instrument.SBSEDModel], default: bool = False)[source]

Bases: BaseModel

Pydantic model for a telescope.

model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class TransmissionModel(*, id: str, name: str, description: str = '', vars: dict[str, float | str] | None=None, wave_range: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22367529c0>, FieldInfo(annotation=NoneType, required=True, description='Instrument minimum and maximum wavelengths.', json_schema_extra={'minShape': '2', 'maxShape': '2', 'exclusiveMinimum': '[0. 0.] nm', 'physType': 'length'})] | None = None, wave: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f2236752900>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'maximum': '100.0 micron', 'minimum': '100.0 nm', 'physType': 'length'})] | None = None, response: Quantity, <pydiet.server.types.quantity.QuantityAnnotation object at 0x7f22367527b0>, FieldInfo(annotation=NoneType, required=True, description='', json_schema_extra={'minShape': '2', 'maxShape': '100000', 'maximum': '100.0', 'minimum': '-100.0', 'physType': 'dimensionless'})] | None = None, spectral: SpectralElement | None = None, default: bool = False)[source]

Bases: BaseModel

Pydantic model for a transmission curve (with wavelength).

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Query models

class ETCQueryModel(*, instrument: InstrumentID = 'megacam', airmass: Annotated[float, Ge(ge=1.0)] = 1.2, aperture: Annotated[float, Gt(gt=0.0), Le(le=15.0)] = 3.0, brightness: Annotated[float, Ge(ge=-100.0), Le(le=1000.0)] = 20.0, compute: Literal['etime', 'snr'] = 'etime', etime: Annotated[float, Ge(ge=0.0), Le(le=1e+30)] = 20.0, exposures: Annotated[int, Ge(ge=1), Le(le=1000000)] = 1, filter: FilterID = 'r', mirror: MirrorID = 'average', photometry: Literal['model_fitting', 'fixed_aperture', 'optimal_aperture', 'large_aperture'] = 'model_fitting', seeing: Annotated[float, Ge(ge=0.1), Le(le=100.0)] = 0.7, sky: Literal['dark', 'grey', 'bright', 'specify'] = 'dark', sky_brightness: Annotated[float, Ge(ge=-100.0), Le(le=1000.0)] = 22.0, sersic_radius: Annotated[float, Gt(gt=0.0), Le(le=10.0)] = 1.0, sersic_index: Annotated[float, Ge(ge=0.3), Le(le=10.0)] = 1.0, sky_unit: Literal['abmag', 'vegamag', 'fmegajy', 'fmujy', 'flux', 'photons'] = 'abmag', snr: Annotated[float, Gt(gt=0.0)] = 10.0, solar: Literal['low', 'average', 'high'] = 'average', source: Literal['point_source', 'galaxy', 'extended'] = 'point_source', stacking: Literal['average', 'median'] = 'median', transparency: Annotated[float, Gt(gt=0.0), Le(le=1.0)] = 1.0, unit: Literal['abmag', 'vegamag', 'fmegajy', 'fmujy', 'flux', 'photons'] = 'abmag')[source]

Bases: BaseModel

Validated inputs for an exposure-time calculator request.

The available filter and mirror identifiers depend on instrument and are checked during model validation. Enum-like fields are stored as their string values.

Examples

>>> query = ETCQueryModel(brightness=22., snr=5.)
>>> (query.compute, query.brightness, query.snr)
('etime', 22.0, 5.0)
classmethod validate_filter(f: str, info: ValidationInfo) → str[source]

Validate a filter identifier against the selected instrument.

Parameters:
  • f (str) -- Filter identifier.

  • info (ValidationInfo) -- Validation context containing the previously validated instrument.

Returns:

f (str) -- The unchanged filter identifier.

Raises:

ETCValidationError -- If the instrument does not provide the filter and f is not "upload".

classmethod validate_mirror(m: str, info: ValidationInfo) → str[source]

Validate a mirror identifier against the selected instrument.

Parameters:
  • m (str) -- Mirror-condition identifier.

  • info (ValidationInfo) -- Validation context containing the previously validated instrument.

Returns:

m (str) -- The unchanged mirror identifier.

Raises:

ETCValidationError -- If the selected instrument does not provide the mirror condition.

model_config = {'arbitrary_types_allowed': True, 'use_enum_values': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Response models

class ETCResponseModel(*, instrument: str, filter: str, compute: Literal['etime', 'snr'], zp: Annotated[float, Ge(ge=-100.0), Le(le=100.0)] = 0.0, zp_instru: Annotated[float, Ge(ge=-100.0), Le(le=100.0)] = 0.0, snr: Annotated[float, Ge(ge=0.0), Lt(lt=1e+30)] = 10.0, etime: Annotated[float, Ge(ge=0.0), Lt(lt=1e+30)] = 1.0, etime_skysat: Annotated[float, Ge(ge=0.0), Lt(lt=1e+30)] = 0.0, etime_sourcesat: Annotated[float, Ge(ge=0.0), Lt(lt=1e+30)] = 0.0, ttime: Annotated[float, Ge(ge=0.0), Lt(lt=1e+30)] = 1.0, bkg_mag: Annotated[float, Ge(ge=-100.0), Le(le=100.0)] = 99.0, bkg_rate: Annotated[float, Ge(ge=0.0), Le(le=1e+30)] = 99.0, lambda_pivot: Annotated[float, Ge(ge=0.0), Lt(lt=1000000000000.0)] = 0.0, bandwidth_rect: Annotated[float, Ge(ge=0.0), Lt(lt=1000000000000.0)] = 0.0, trans_peak: Annotated[float, Ge(ge=0.0), Le(le=1.0)] = 1.0, trans_peak_instru: Annotated[float, Ge(ge=0.0), Le(le=1.0)] = 1.0, cutout: str | None = None, filter_transmission: Json | None = None, atmosphere_transmission: Json | None = None)[source]

Bases: BaseModel

Results returned by the exposure-time calculator.

Numerical timing values are in seconds, wavelengths and bandwidths are in nanometres, and zero points and background surface brightnesses are in AB magnitudes. Optional transmission fields contain JSON-encoded transmission models and cutout may contain a base64 data URL.

Examples

>>> response = ETCResponseModel(
...     instrument="Demo", filter="g", compute="etime"
... )
>>> (response.etime, response.snr, response.cutout)
(1.0, 10.0, None)
model_config = {'use_enum_values': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

Custom types for PyDIET data models

class FilterID(*values)

Bases: str, Enum

class InstrumentID(*values)

Bases: str, Enum

class MirrorID(*values)

Bases: str, Enum