# Observation Model ```{eval-rst} .. verified:: 2026-05-07 :reviewer: Yoko Okada ``` This section explains how scientific observations are planned and executed in ops-db. There is a key distinction between **planning** (what we want to observe) and **execution** (what we actually observed). ## Planning Layer The planning layer defines what observations should be performed. These are relatively stable entities that can be updated over time. ### Planning Hierarchy ```{eval-rst} .. mermaid:: graph TB PROG[ObservingProgram] SUB[SubObservingProgram] OU[ObsUnit] SRC[Source] OBSMODE[ObsMode] CONFIG[ObservationConfiguration] IMCONFIG[InstrumentModuleConfiguration] PROG -->|has many| SUB PROG -->|has many| OU SUB -->|has many| OU SRC -->|observed by| OU OBSMODE -->|defines strategy for| OU CONFIG -->|configures| OU IMCONFIG -->|used in| OU style PROG fill:#e1f5ff style SUB fill:#e1f5ff style OU fill:#e1f5ff style SRC fill:#ffe1f5 style OBSMODE fill:#e1ffe1 style CONFIG fill:#ffe1f5 ``` ### ObservingProgram {py:class}`~ccat_ops_db.models.ObservingProgram` groups observations under a scientific and technical program. It basically corresponds to "survey" for Prime-Cam projects (CCAT-prime collaboration et al. 2021), and Galactic Ecology is the CHAI project. When refering, usually "short_name" attriubte is used ("GEco" instead of "Galactic Ecology"). Technical programs include "Calibration" ("Cal") or "Engineering" ("ENG"). For complete attribute details, see {py:class}`~ccat_ops_db.models.ObservingProgram`. ### SubObservingProgram {py:class}`~ccat_ops_db.models.SubObservingProgram` breaks a program into smaller scientific sub-projects. Not all {py:class}`~ccat_ops_db.models.ObsUnit` objects need to belong to a {py:class}`~ccat_ops_db.models.SubObservingProgram`. Practically this is only relevant for "GEco". For complete attribute details, see {py:class}`~ccat_ops_db.models.SubObservingProgram`. ### Source {py:class}`~ccat_ops_db.models.Source` represents the astronomical target to be observed. It is a polymorphic base class with three concrete types: **FixedSource** - Objects with fixed celestial coordinates (stars, galaxies, nebulae). : **Example**: IRC10216 as a FixedSource **SolarSystemObject** - Planets, asteroids, comets. : **Example**: Jupiter as a SolarSystemObject **ConstantElevationSource** - Objects used for surveys with the constant elevation mode. It specifies the survey area by the boundery celestial coordinates (in RA/DEC or Galactic). : **Example**: COSMOS_CE as a ConstantElevationSource For complete attribute details, see {py:class}`~ccat_ops_db.models.Source`, {py:class}`~ccat_ops_db.models.FixedSource`, {py:class}`~ccat_ops_db.models.SolarSystemObject`, and {py:class}`~ccat_ops_db.models.ConstantElevationSource`. ### ObsUnit {py:class}`~ccat_ops_db.models.ObsUnit` defines a schedulable observation unit - the fundamental building block of observing. This is a "template" for observations - it can be executed multiple times, producing multiple {py:class}`~ccat_ops_db.models.ExecutedObsUnit` records. For complete attribute details, see {py:class}`~ccat_ops_db.models.ObsUnit`. ### ObsMode {py:class}`~ccat_ops_db.models.ObsMode` defines the observing mode, practically scanning patterns. **Examples**: : - CHAI: "otf_totalpower_map" (on-the-fly mapping) - PrimeCam: "constant_elevation" (constant elevation, constant azimuth velocity scans) For complete attribute details, see {py:class}`~ccat_ops_db.models.ObsMode`. ### ObservationConfiguration {py:class}`~ccat_ops_db.models.ObservationConfiguration` provides detailed parameters for how to execute the observation. It is polymorphic with subclasses for different instrument types: {py:class}`~ccat_ops_db.models.ChaiObservationConfiguration` for CHAI and miniCHAI observations and {py:class}`~ccat_ops_db.models.PrimeCamObservationConfiguration` for Prime-Cam and Mod-Cam observations. The common part contains azimuth range parameters (only relevant for constant elevation scans), and the subclasses contain remaining parameters that can be loaded by the observation execution system. For CHAI, we store the what traditionally was contained in the `inpar` and `tiling` files under the Tables {py:class}`~ccat_ops_db.models.ChaiTiling` and {py:class}`~ccat_ops_db.models.ChaiInparParameter` which are linked to the {py:class}`~ccat_ops_db.models.ChaiObservationConfiguration` Table. For Prime-Cam, {py:class}`~ccat_ops_db.models.PrimeCamObservationConfiguration` has an attribute mapping_parameters, where all parameters can be stored as a json entry. For complete attribute details, see {py:class}`~ccat_ops_db.models.ObservationConfiguration`, {py:class}`~ccat_ops_db.models.ChaiObservationConfiguration`, and {py:class}`~ccat_ops_db.models.PrimeCamObservationConfiguration`. ### InstrumentModuleConfiguration {py:class}`~ccat_ops_db.models.InstrumentModuleConfiguration` defines configurations of a particular {py:class}`~ccat_ops_db.models.InstrumentModule` (module for Prime-Cam, array for CHAI) used for observing. It is also polymorphic with subclasses for different instrument types: {py:class}`~ccat_ops_db.models.ChaiModuleConfiguration` for CHAI and miniCHAI observations and {py:class}`~ccat_ops_db.models.PrimeCamModuleConfiguration` for Prime-Cam and Mod-Cam. {py:class}`~ccat_ops_db.models.ChaiModuleConfiguration` contains line information to be tuned through {py:class}`~ccat_ops_db.models.Line` and the IF value. Both subclass contains config_params as a free json field to record any useful instrument-related parameters. So far it is only used to distinguish whether the FPI steps cycles or not (one fixed FPI step) for Prime-Cam/EoR-Spec. Each {py:class}`~ccat_ops_db.models.ObsUnit` has attributes primary_instrument_module_configuration and instrument_module_configurations: the former points a specific {py:class}`~ccat_ops_db.models.InstrumentModuleConfiguration`, specifying the primary (science-driver) instrument module, the latter is a list of {py:class}`~ccat_ops_db.models.InstrumentModuleConfiguration`, including parallel modules. ### PreScheduledSlot {py:class}`~ccat_ops_db.models.PreScheduledSlot` defines fixed time windows for specific observation units. Used for observations that must happen at specific times. For the moment it is used only as regularly assigned slots for WFS, but can be also used for time-critical transients when it happens. For complete attribute details, see {py:class}`~ccat_ops_db.models.PreScheduledSlot`. ## Execution Layer ### ExecutedObsUnit {py:class}`~ccat_ops_db.models.ExecutedObsUnit` records an actual execution of an {py:class}`~ccat_ops_db.models.ObsUnit`. One {py:class}`~ccat_ops_db.models.ObsUnit` can have many {py:class}`~ccat_ops_db.models.ExecutedObsUnit` records (repeated observations). Uses UUID instead of integer ID because these are created by observing systems that may not have database connectivity at creation time (see {doc}`/ops-db-api/docs/deep-dive/transaction-buffering`). For complete attribute details, see {py:class}`~ccat_ops_db.models.ExecutedObsUnit`. ## Execution Flow ```{eval-rst} .. mermaid:: sequenceDiagram participant Planner participant Scheduler participant Instrument participant DataAcq Planner->>ObsUnit: Create ObsUnit with Source, ObsMode, Config etc. Scheduler->>ObsUnit: Select based on priorities/constraints Scheduler->>Instrument: Suggest observation Instrument->>ExecutedObsUnit: Create ExecutedObsUnit record Instrument->>DataAcq: Execute observation DataAcq->>RawDataFile: Create RawDataFile records DataAcq->>ExecutedObsUnit: Link data to execution ``` ## The Planning → Execution Flow 1. **ObservingProgram** defines the science case 2. **ObsUnits** are created with Sources, ObsModes, ObservationConfigurations, and InstrumentModuleConfigurations 3. **Scheduler** selects ObsUnits based on priorities, constraints, and conditions 4. **Instrument Control** executes → creates **ExecutedObsUnit** 5. **Data acquisition** creates **RawDataFiles** linked to the ExecutedObsUnit ## Why This Structure? **Separation of Planning and Execution** : Allows: - Repeating observations (observe the same target multiple times) - Tracking actual vs. planned (e.g., if an observation is interrupted) - Updating plans without affecting historical records **Version and History Tracking** The ``version`` and ``history`` fields exist on {py:class}`~ccat_ops_db.models.ObsUnit`, {py:class}`~ccat_ops_db.models.Source`, {py:class}`~ccat_ops_db.models.PrimeCamObservationConfiguration`, {py:class}`~ccat_ops_db.models.ChaiTiling`, and {py:class}`~ccat_ops_db.models.ChaiInparParameter`. They are updated automatically with a timestamp whenever their contents have been updated through the API to preserve provenance. **Polymorphic Source Model** : Accommodates different target types (fixed stars vs. moving planets vs. survey areas) without requiring separate observation models. **Configuration Layer** : The configuration layer (ObservationConfiguration, InstrumentModuleConfiguration) provides instrument-specific parameters while keeping the core ObsUnit model general. ## Related Documentation - Complete API reference: {doc}`../api_reference/models` - Observatory hierarchy: {doc}`observatory_hierarchy` - Data model: {doc}`data_model` - Data transfer workflows: {doc}`/data-transfer/docs/index`