Source code for tom_observations.models

from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models


from tom_observations.facility import get_service_class
from tom_common.hooks import run_hook
from tom_targets.base_models import BaseTarget


[docs] class ObservationRecord(models.Model): """ Class representing an observation in a TOM. A ObservationRecord corresponds with any set of related exposures at a facility, and is associated with a single target. :param target: The ``Target`` with which this object is associated. :type target: Target :param facility: The facility at which this observation is taken. Should be the name specified in the corresponding TOM facility module, if one exists. :type facility: str :param parameters: The set of parameters used in the API request made to create the observation :type parameters: dict :param status: The current status of the observation. Should be a valid status in the corresponding TOM facility module, if one exists. :type status: str :param scheduled_start: The time at which the observation is scheduled to begin, according to the facility. :type scheduled_start: datetime :param scheduled_end: The time at which the observation is scheduled to end, according to the facility. :type scheduled_end: datetime :param created: The time at which this object was created. :type created: datetime :param modified: The time at which this object was last updated. :type modified: datetime """ target = models.ForeignKey(BaseTarget, on_delete=models.CASCADE) user = models.ForeignKey(User, null=True, default=None, on_delete=models.DO_NOTHING) facility = models.CharField(max_length=50) parameters = models.JSONField() observation_id = models.CharField(max_length=255) status = models.CharField(max_length=200) scheduled_start = models.DateTimeField(null=True) scheduled_end = models.DateTimeField(null=True) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: ordering = ('-created',)
[docs] def save(self, *args, **kwargs): if self.id: presave_data = ObservationRecord.objects.get(pk=self.id) super().save(*args, **kwargs) if self.status != presave_data.status: run_hook('observation_change_state', self, presave_data.status) else: super().save(*args, **kwargs) run_hook('observation_change_state', self, None)
@property def terminal(self): facility = get_service_class(self.facility) return self.status in facility().get_terminal_observing_states() @property def failed(self): facility = get_service_class(self.facility) return self.status in facility().get_failed_observing_states() @property def url(self): facility = get_service_class(self.facility) return facility().get_observation_url(self.observation_id) def update_status(self): facility = get_service_class(self.facility) facility().update_observation_status(self.observation_id) def save_data(self): facility = get_service_class(self.facility) facility().save_data_products(self) def __str__(self): return '{0} @ {1}'.format(self.target, self.facility)
[docs] class ObservationGroup(models.Model): """ Class representing a logical group of observations. :param name: The name of the grouping. :type name: str :param observation_records: Set of ``ObservationRecord`` objects associated with this ``ObservationGroup`` :param created: The time at which this ``ObservationGroup`` was created. :type created: datetime :param modified: The time at which this ``ObservationGroup`` was modified. :type modified: datetime """ name = models.CharField(max_length=50) observation_records = models.ManyToManyField(ObservationRecord) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: ordering = ('-created', 'name',) def __str__(self): return self.name
[docs] class DynamicCadence(models.Model): """ Class representing a dynamic cadence--that is, a cadence that follows a pattern but modifies its behavior depending on the result of prior observations. :param observation_group: The ``ObservationGroup`` containing the observations that were created by this cadence. :type observation_group: ``ObservationGroup`` :param cadence_strategy: The name of the cadence strategy this cadence is using. :type cadence_strategy: str :param cadence_parameters: The parameters for this cadence, e.g. cadence period :type cadence_parameters: JSON :param active: Whether or not this cadence should continue to submit observations :type active: boolean :param created: The time at which this ``DynamicCadence`` was created. :type created: datetime :param modified: The time at which this ``DynamicCadence`` was modified. :type modified: datetime """ observation_group = models.ForeignKey(ObservationGroup, null=False, default=None, on_delete=models.CASCADE) cadence_strategy = models.CharField(max_length=100, blank=False, default=None, verbose_name='Cadence strategy used for this DynamicCadence') cadence_parameters = models.JSONField(blank=False, null=False, verbose_name='Cadence-specific parameters') active = models.BooleanField(verbose_name='Active', help_text='''Whether or not this DynamicCadence should continue to submit observations.''') created = models.DateTimeField(auto_now_add=True, help_text='The time which this DynamicCadence was created.') modified = models.DateTimeField(auto_now=True, help_text='The time which this DynamicCadence was modified.') def __str__(self): return f'{self.cadence_strategy} with parameters {self.cadence_parameters}'
[docs] class ObservationTemplate(models.Model): """ Class representing an observation template. :param name: The name of the ``ObservationTemplate`` :type name: str :param facility: The module-specified facility name for which the template is valid :type facility: str :param parameters: Observing parameters :type parameters: dict :param created: The time at which this ``ObservationTemplate`` was created. :type created: datetime :param modified: The time at which this ``ObservationTemplate`` was modified. :type modified: datetime """ name = models.CharField(max_length=200) facility = models.CharField(max_length=50) parameters = models.JSONField() created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) def __str__(self): return self.name
[docs] class Facility(models.Model): """ Class representing individual telescope facilities. :param site_code: Short-hand code used to reference the facility :type site_code: str :param mpc_observatory_code: Three-digit reference code for the facility from the Minor Planet Center :type mpc_observatory_code: str :param full_name: Name of the facility :type full_name: str :param short_name: Abbreviated name for the facility :type short_name: str :param location: Location of observatory :type location: str choice field :param latitude: Latitude of facility if Earth-based in decimal degrees :type latitude: float :param longitude: Langitude of facility if Earth-base in decimal degrees :type longitude: float :param elevation: Elevation of facility above mean sealevel if Earth-based :type elevation: float, may be negative :param orbit: Type of orbit if facility is space-based :type orbit: str choice field :param diameter: Diameter of primary optic or detector :type diameter: float :param typical_seeing: Typical seeing at the facility, units of arcsec :type typical_seeing: float :param detector_type: Descriptor of the messenger or wavelength range measured by the facility :type detector_type: str :param info_url: URL where more information on the facility can be found :type info_url: URL :param api_url: URL of the facility's API if any :type api_url: URL """ LOCATION_OPTIONS = [ ("ground", "Ground-based"), ("space", "Space-based") ] ORBIT_OPTIONS = [ ("leo", "Low-Earth Orbit"), ("l2", "Lagrange Point 2"), ("earth-trailing", "Earth-trailing orbit"), ("geosync", "Geosynchronous orbit"), ("polar", "Polar orbit"), ("elliptical", "Elliptical orbit") ] DETECTOR_OPTIONS = [ ("gammaray", "Gammay-ray"), ("xray", "X-ray"), ("uv", "Ultraviolet"), ("optical", "Optical"), ("nir", "Near Infrared"), ("uvoir", "UV/optical/NIR"), ("submm", "Submillimeter"), ("microwave", "Microwave"), ("radio", "Radio"), ("gw", "Gravitational Waves"), ("neutrino", "Neutrinos"), ("cherenkov", "Cherenkov radiation"), ("multiband", "Multiple detectors") ] site_code = models.CharField( max_length=20, null=True, blank=True, help_text="Short-hand identifier for the facility" ) mpc_observatory_code = models.CharField( max_length=3, null=True, blank=True, help_text="<a href='https://minorplanetcenter.net/iau/lists/ObsCodesF.html'>" "MPC Observatory Code List</a>" ) full_name = models.CharField(max_length=100) short_name = models.CharField(max_length=50) location = models.CharField(max_length=15, choices=LOCATION_OPTIONS) latitude = models.FloatField( validators=[MinValueValidator(-90.0), MaxValueValidator(90.0)], null=True, blank=True, help_text="Latitude in decimal degrees" ) longitude = models.FloatField( validators=[MinValueValidator(-180.0), MaxValueValidator(180.0)], null=True, blank=True, help_text="Longitude in decimal degrees" ) elevation = models.FloatField( validators=[MinValueValidator(-3000.0), MaxValueValidator(6000.0)], null=True, blank=True, help_text="Elevation in meters" ) orbit = models.CharField( max_length=20, choices=ORBIT_OPTIONS, null=True, blank=True, help_text="Orbit regime of space-based facility" ) diameter = models.FloatField( validators=[MinValueValidator(0.0), MaxValueValidator(600.0)], null=True, blank=True, help_text="Diameter of primary detector in meters" ) typical_seeing = models.FloatField( validators=[MinValueValidator(0.0), MaxValueValidator(15.0)], null=True, blank=True, help_text="Seeing in arcsec" ) detector_type = models.CharField( max_length=30, choices=DETECTOR_OPTIONS, help_text="Electromagnetic wavelength or messenger type detected" ) info_url = models.URLField( max_length=400, null=True, blank=True, help_text="URL of website where more information about the facility can be found" ) api_url = models.URLField( max_length=200, null=True, blank=True, help_text="Root URL of the facilities API endpoints" ) class Meta: verbose_name_plural = "facilities" def __str__(self): return self.short_name