Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TNS API fix and a few others #282

Merged
merged 19 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import os
from pathlib import Path

APP_VERSION = '1.0.5'
APP_VERSION = '1.0.6'

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
Expand Down
3 changes: 2 additions & 1 deletion app/host/cutouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def download_and_save_cutouts(
(not file_exists or not cutout_exists)
and cutout_object.message != "No image found"
) or not overwrite == "False":
if not file_exists and cutout_object.message != "No image found":
status = 0
if cutout_object.message != "No image found":
fits, status, err = cutout(transient.sky_coord, filter, fov=fov)

if fits:
Expand Down
1 change: 0 additions & 1 deletion app/host/host_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ def do_aperture_photometry(image, sky_aperture, filter):
magnitude, magnitude_error = None, None
if flux != flux or flux_error != flux_error:
flux, flux_error = None, None

# wave_eff = filter.transmission_curve().wave_effective
return {
"flux": flux,
Expand Down
48 changes: 48 additions & 0 deletions app/host/migrations/0028_aperture_software_version_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Generated by Django 5.0.8 on 2025-03-08 00:54

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('host', '0027_transient_image_trim_status'),
]

operations = [
migrations.AddField(
model_name='aperture',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='aperturephotometry',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='cutout',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='host',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='sedfittingresult',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='starformationhistoryresult',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='transient',
name='software_version',
field=models.CharField(blank=True, max_length=50, null=True),
),
]
37 changes: 33 additions & 4 deletions app/host/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def dec(self):
"""
return self.sky_coord.dec.to_string(precision=2)

def save(self, *args, **kwargs):
self.software_version = settings.APP_VERSION
super(SkyObject, self).save(*args, **kwargs)

class Host(SkyObject):
"""
Expand All @@ -85,7 +88,8 @@ class Host(SkyObject):
photometric_redshift = models.FloatField(null=True, blank=True)
milkyway_dust_reddening = models.FloatField(null=True, blank=True)
objects = HostManager()

software_version = models.CharField(max_length=50, blank=True, null=True)


class Transient(SkyObject):
"""
Expand Down Expand Up @@ -125,7 +129,8 @@ class Transient(SkyObject):
image_trim_status = models.CharField(max_length=20, default="not ready")
added_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
progress = models.IntegerField(default=0)

software_version = models.CharField(max_length=50, blank=True, null=True)

@property
def best_redshift(self):
"""get the best redshift for a transient"""
Expand Down Expand Up @@ -405,11 +410,16 @@ class Cutout(models.Model):
)
fits = models.FileField(upload_to=fits_file_path, null=True, blank=True)
message = models.CharField(max_length=50, null=True, blank=True)

software_version = models.CharField(max_length=50, blank=True, null=True)

# used if some downloads fail
# warning = models.BooleanField(default=False)
objects = CutoutManager()

def save(self, *args, **kwargs):
self.software_version = settings.APP_VERSION
super(Cutout, self).save(*args, **kwargs)


class Aperture(SkyObject):
"""
Expand All @@ -425,6 +435,8 @@ class Aperture(SkyObject):
semi_major_axis_arcsec = models.FloatField()
semi_minor_axis_arcsec = models.FloatField()
type = models.CharField(max_length=20)
software_version = models.CharField(max_length=50, blank=True, null=True)

objects = ApertureManager()

def __str__(self):
Expand Down Expand Up @@ -468,7 +480,8 @@ class AperturePhotometry(models.Model):
magnitude = models.FloatField(blank=True, null=True)
magnitude_error = models.FloatField(blank=True, null=True)
is_validated = models.CharField(blank=True, null=True, max_length=40)

software_version = models.CharField(max_length=50, blank=True, null=True)

@property
def flux_rounded(self):
return round(self.flux, 2)
Expand All @@ -477,6 +490,10 @@ def flux_rounded(self):
def flux_error_rounded(self):
return round(self.flux_error, 2)

def save(self, *args, **kwargs):
self.software_version = settings.APP_VERSION
super(AperturePhotometry, self).save(*args, **kwargs)


class StarFormationHistoryResult(models.Model):

Expand All @@ -493,7 +510,13 @@ class StarFormationHistoryResult(models.Model):
logsfr_tmin = models.FloatField(null=True, blank=True)
logsfr_tmax = models.FloatField(null=True, blank=True)

software_version = models.CharField(max_length=50, blank=True, null=True)

def save(self, *args, **kwargs):
self.software_version = settings.APP_VERSION
super(StarFormationHistoryResult, self).save(*args, **kwargs)


class SEDFittingResult(models.Model):
"""Model to store prospector results"""

Expand Down Expand Up @@ -571,6 +594,12 @@ class SEDFittingResult(models.Model):
upload_to=npz_percentiles_file_path, null=True, blank=True
)
model_file = models.FileField(upload_to=npz_model_file_path, null=True, blank=True)
software_version = models.CharField(max_length=50, blank=True, null=True)

def save(self, *args, **kwargs):
self.software_version = settings.APP_VERSION
super(SEDFittingResult, self).save(*args, **kwargs)


class TaskRegisterSnapshot(models.Model):
"""
Expand Down
94 changes: 45 additions & 49 deletions app/host/system_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from host.base_tasks import SystemTaskRunner
from host.base_tasks import task_soft_time_limit
from host.base_tasks import task_time_limit
from host.workflow import reprocess_transient
from host.workflow import transient_workflow
from host.trim_images import trim_images

Expand All @@ -32,61 +33,56 @@ def run_process(self, interval_minutes=200):
now = timezone.now()
time_delta = datetime.timedelta(minutes=interval_minutes)
tns_credentials = get_tns_credentials()
recent_transients = get_transients_from_tns(
transients_from_tns = get_transients_from_tns(
now - time_delta, tns_credentials=tns_credentials
)

print("TNS DONE")
saved_transients = Transient.objects.all()
count = 0
for transient in recent_transients:
print(transient.name)
try:
saved_transient = saved_transients.get(
name__exact=transient.name)
if saved_transient.public_timestamp.replace(tzinfo=None) - parser.parse(
transient.public_timestamp
) == datetime.timedelta(0):
continue

# if there was *not* a redshift before and there *is* one now
# then it would be safest to reprocess everything
if not saved_transient.redshift and transient.redshift:
tasks = TaskRegister.objects.filter(
transient=saved_transient)
for t in tasks:
### TODO: this could be smarter
### we don't *always* need to re-process every stage
t.status = Status.objects.get(message="not processed")
t.save()

# update info
new_transient_dict = transient.__dict__
if "host_id" in new_transient_dict.keys():
if saved_transient.host_id is not None:
new_transient_dict["host_id"] = saved_transient.host_id
else:
del new_transient_dict["host_id"]

keys_to_del = [
"_state",
"id",
"progress",
"tasks_initialized",
"photometric_class",
"milkyway_dust_reddening",
"processing_status",
]
for k in keys_to_del:
del new_transient_dict[k]
new_transient_dict['tasks_initialized'] = False
saved_transients.filter(name__exact=transient.name).update(
**new_transient_dict
)

except Transient.DoesNotExist:
transient.save()
for transient_from_tns in transients_from_tns:
print(transient_from_tns.name)

# If the transient has not already been ingested, save the TNS
# data and proceed to the next transient
saved_transient = saved_transients.filter(name__exact=transient_from_tns.name)
if not saved_transient:
transient_from_tns.save()
count += 1
continue
# If the transient was previously ingested, compare to the incoming TNS data.
saved_transient = saved_transient[0]

# Determine if the redshift value changed or was added.
redshift_updated = False
if transient_from_tns.redshift:
redshift_updated = \
not saved_transient.redshift or \
saved_transient.redshift != transient_from_tns.redshift

# Determine if the timestamps are different.
saved_timestamp = saved_transient.public_timestamp.replace(tzinfo=None)
tns_timestamp = parser.parse(transient_from_tns.public_timestamp)
identical_timestamps = saved_timestamp - tns_timestamp == datetime.timedelta(0)
# If the timestamps are identical and there was no redshift update, skip to the next TNS transient.
if identical_timestamps and not redshift_updated:
continue

# Update the saved transient data with the latest TNS data
saved_transient.tns_id = transient_from_tns.tns_id
saved_transient.ra_deg = transient_from_tns.ra_deg
saved_transient.dec_deg = transient_from_tns.dec_deg
saved_transient.tns_prefix = transient_from_tns.tns_prefix
saved_transient.public_timestamp = transient_from_tns.public_timestamp
saved_transient.spectroscopic_class = transient_from_tns.spectroscopic_class
saved_transient.redshift = transient_from_tns.redshift
# Reinitialize the transient state so that its processing workflow will run again if necessary.
saved_transient.tasks_initialized = False
saved_transient.save()

# If the redshift value was updated, reprocess the entire workflow.
if redshift_updated:
reprocess_transient(slug=saved_transient.name)

print(f"Added {count} new transients")
print("TNS UPLOADED")

Expand Down
1 change: 0 additions & 1 deletion app/host/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from host.system_tasks import SnapshotTaskRegister
from host.system_tasks import TNSDataIngestion
from host.system_tasks import TrimTransientImages
from .transient_name_server import get_transients_from_tns_by_name


periodic_tasks = [
Expand Down
13 changes: 13 additions & 0 deletions app/host/templates/host/photometry_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ <h4>Aperture details</h4>
<th scope="col">Flux error {% latexify '{\rm (\mu Jy)}' math_inline=True %}</th>
<th scope="col">Mag</th>
<th scope="col">Mag error</th>
<th scope="col">Mag sys</th>
</tr>
</thead>
<tbody>
Expand All @@ -45,6 +46,11 @@ <h4>Aperture details</h4>
<td>{{item.flux_error_rounded}}</td>
<td>{{item.magnitude|floatformat:3}}</td>
<td>{{item.magnitude_error|floatformat:3}}</td>
{% if item.filter.ab_offset == 0 %}
<td>AB</td>
{% else %}
<td>Vega</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
Expand Down Expand Up @@ -72,6 +78,7 @@ <h4>Aperture details</h4>
<th scope="col">Flux error {% latexify '{\rm (\mu Jy)}' math_inline=True %}</th>
<th scope="col">Mag</th>
<th scope="col">Mag error</th>
<th scope="col">Mag sys</th>
</tr>
</thead>
<tbody>
Expand All @@ -82,6 +89,12 @@ <h4>Aperture details</h4>
<td>{{item.flux_error_rounded}}</td>
<td>{{item.magnitude|floatformat:3}}</td>
<td>{{item.magnitude_error|floatformat:3}}</td>
{% if item.filter.ab_offset == 0 %}
<td>AB</td>
{% else %}
<td>Vega</td>
{% endif %}

</tr>
{% endfor %}
</tbody>
Expand Down
8 changes: 3 additions & 5 deletions app/host/transient_name_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from .models import Transient


def get_tns_credentials():
"""
Retrieves TNS credentials from environment variables
Expand Down Expand Up @@ -152,7 +151,7 @@ def get_transients_from_tns_by_name(

transients = []
for t in transient_list:
transients += [{"objname": t, "objid": t}]
transients += [{"objname": t}]

blast_transients = []

Expand Down Expand Up @@ -183,7 +182,7 @@ def tns_to_blast_transient(tns_transient):
tns_prefix=tns_transient["name_prefix"],
public_timestamp=tns_transient["discoverydate"],
spectroscopic_class=tns_transient["object_type"]["name"],
redshift=tns_transient["redshift"],
redshift=tns_transient["redshift"]
)
return blast_transient

Expand All @@ -206,7 +205,7 @@ def tns_staging_blast_transient(tns_transient):
dec_deg=tns_transient["declination"],
tns_prefix=tns_transient["name_prefix"],
public_timestamp=tns_transient["discoverydate"],
spectroscopic_class=tns_transient["type"],
spectroscopic_class=tns_transient["type"]
)
return blast_transient

Expand Down Expand Up @@ -303,7 +302,6 @@ def build_tns_get_query_data(tns_bot_api_key, transient):
"""
get_obj = [
("objname", transient["objname"]),
("objid", transient["objid"]),
("photometry", "0"),
("spectra", "0"),
]
Expand Down
Loading