-
Nico Vermaas authoredNico Vermaas authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
test_calculated_qualities.py 11.05 KiB
from django.test import TestCase
import json
import taskdatabase.tests.test_calculated_qualities_outputs as outputs
from taskdatabase.services import calculated_qualities as qualities
from taskdatabase.models import Configuration, Task, Workflow
from taskdatabase.services.common import get_summary_flavour, SummaryFlavour
class TestCalculatedQualities(TestCase):
@classmethod
def setUpTestData(cls):
print("setUpTestData: Run once to set up non-modified data for all class methods.")
# Set up non-modified objects used by all test methods
quality_thresholds = {
"moderate": 20,
"poor": 50,
"overall_poor": 50,
"overall_good": 90,
}
Configuration.objects.create(key="quality_thresholds", value=json.dumps(quality_thresholds))
def setUp(self):
print("setUp: Run once for every test method to setup clean data.")
# tasks without summary information (not allowed according to the interface definition)
workflow_no_summary = Workflow(workflow_uri="unknown_workflow_no_summary")
workflow_no_summary.save()
Task.objects.get_or_create(sas_id=33333, status='processed', outputs=outputs.no_summary, workflow=workflow_no_summary)
# create a list of Tasks with various values of rfi_percent to test the quality algorithms
workflow_requantisation = Workflow(workflow_uri="psrfits_requantisation")
workflow_requantisation.save()
# rfi_percent=0
Task.objects.get_or_create(sas_id=54321, status='processed', outputs=outputs.default_summary_flavour_with_rfi_percent_zero_1, workflow=workflow_requantisation)
# rfi_percent 11,22,31,52
Task.objects.get_or_create(sas_id=54321, status='processed', outputs=outputs.default_summary_flavour_with_rfi_1, workflow=workflow_requantisation)
Task.objects.get_or_create(sas_id=54321, status='processed', outputs=outputs.default_summary_flavour_with_rfi_2, workflow=workflow_requantisation)
Task.objects.get_or_create(sas_id=54321, status='processed', outputs=outputs.default_summary_flavour_with_rfi_3, workflow=workflow_requantisation)
Task.objects.get_or_create(sas_id=54321, status='processed', outputs=outputs.default_summary_flavour_with_rfi_4, workflow=workflow_requantisation)
# tasks without rfi_percent (so simulating an yet unknown pipeline with summary information, but no rfi percentage)
workflow_no_rfi = Workflow(workflow_uri="unknown_workflow")
workflow_no_rfi.save()
Task.objects.get_or_create(sas_id=12345, status='processed', outputs=outputs.default_summary_flavour_without_rfi_1, workflow=workflow_no_rfi)
# workflow_imaging_compression, rfi_percentage=1.7186448587105623
workflow_imaging_compression = Workflow(workflow_uri="imaging_compress_pipeline_v011")
workflow_imaging_compression.save()
Task.objects.get_or_create(sas_id=55555, status='processed', outputs=outputs.imaging_compression_summary_flavor_with_rfi_1, workflow=workflow_imaging_compression)
# LINK pipelines (no rfi_percent onboard yet)
workflow_link_calibrator = Workflow(workflow_uri="linc_calibrator_v4_2")
workflow_link_calibrator.save()
Task.objects.get_or_create(sas_id=666666, status='processed', outputs=outputs.link_calibrator_summary_without_rfi, workflow=workflow_link_calibrator)
workflow_link_target = Workflow(workflow_uri="linc_target_v4_2")
workflow_link_target.save()
Task.objects.get_or_create(sas_id=666667, status='processed', outputs=outputs.link_target_summary_without_rfi, workflow=workflow_link_target)
def test_run_calculations_when_task_becomes_stored(self):
for task in Task.objects.all():
task.new_status = 'stored'
# this triggers the overridden save function in models.task
task.save()
# only 4 of the 7 tasks should now have calculated_qualities
count = 0
for task in Task.objects.all():
if task.calculated_qualities['per_sasid']:
count += 1
self.assertEqual(count,6)
def test_calculated_qualities(self):
"""
calculate the quality per task and per sas_id based on rfi_percent values
The threshold values are written from a configuration jsonfield
Using this algorithm from SDCO:
rfi_i <= 20 % is good
20% <= rfi_i <= 50 is moderate
rfi_i > 50 is poor.
except when rfi_percent = 0
Using this algorithm from SDCO:
if more then 90 % of all files have a good quality then the dataset has good condition.
If more then 50 % of all files have a poor quality then the dataset is poor
otherwise is moderate.
"""
# read the quality thresholds from the test database
quality_thresholds = json.loads(Configuration.objects.get(key="quality_thresholds").value)
# get the tasks for sas_id 54321
tasks_for_this_sasid = Task.objects.filter(sas_id=54321)
# run the algorithms and gather the values
quality_values = {'poor': 0, 'moderate': 0, 'good': 0}
for task in tasks_for_this_sasid:
q = qualities.calculate_qualities(task, tasks_for_this_sasid, quality_thresholds)
try:
key = task.calculated_qualities['per_task']
quality_values[key] = quality_values[key] + 1
quality_per_sasid = task.calculated_qualities['per_sasid']
except:
# ignore the tasks that have no calculated quality.
pass
self.assertEqual(quality_values,{'poor': 1, 'moderate': 2, 'good': 2})
# not 90% = good, and not >50% = poor so 'moderate'
self.assertEqual(quality_per_sasid,'moderate')
def test_calculated_qualities_with_optimistic_thresholds(self):
"""
calculate the quality per task and per sas_id based on rfi_percent values
The threshold values are extremely optimistic, simulating changes made by the user
Using this algorithm from SDCO:
rfi_i <= 50 % is good
50% <= rfi_i <= 90 is moderate
rfi_i > 90 is poor.
except when rfi_percent = 0
Using this algorithm from SDCO:
if more then 50 % of all files have a good quality then the dataset has good condition.
If more then 10 % of all files have a poor quality then the dataset is poor
otherwise is moderate.
"""
# optimistic thresholds, poor data doesn't exist
quality_thresholds = {
"moderate": 50,
"poor": 90,
"overall_poor": 10,
"overall_good": 50,
}
# get the tasks for sas_id 54321
tasks_for_this_sasid = Task.objects.filter(sas_id=54321)
# run the algorithms and gather the values
quality_values = {'poor': 0, 'moderate': 0, 'good': 0}
for task in tasks_for_this_sasid:
q = qualities.calculate_qualities(task, tasks_for_this_sasid, quality_thresholds)
try:
key = task.calculated_qualities['per_task']
quality_values[key] = quality_values[key] + 1
quality_per_sasid = task.calculated_qualities['per_sasid']
except:
# ignore the tasks that have no calculated quality.
pass
# rfi_percentages are 11,22,31,52 for the tasks of this sasid
# with the optimistic parameters that means that the first 3 are 'good', and last one is moderate. No poor
self.assertEqual(quality_values,{'poor': 0, 'moderate': 1, 'good': 4})
# 3 out of 4 are 'good', 75% is above the 50% threshold, so 'good'
self.assertEqual(quality_per_sasid,'good')
def test_faulty_thresholds(self):
"""
what happens if the user makes a typo in the threshold?
"""
# faulty thresholds
quality_thresholds = {
"moderate": "a",
"poor": 50,
"overall_poor": 50,
"overall_good": 90,
}
# get the tasks for sas_id 54321
tasks_for_this_sasid = Task.objects.filter(sas_id=54321)
# run the algorithms and gather the values
quality_values = {'poor': 0, 'moderate': 0, 'good': 0}
quality_per_sasid = None
for task in tasks_for_this_sasid:
q = qualities.calculate_qualities(task, tasks_for_this_sasid, quality_thresholds)
try:
key = task.calculated_qualities['per_task']
quality_values[key] = quality_values[key] + 1
quality_per_sasid = task.calculated_qualities['per_sasid']
except:
# ignore the tasks that have no calculated quality.
pass
self.assertEqual(quality_values, {'poor': 0, 'moderate': 0, 'good': 0})
self.assertEqual(quality_per_sasid, None)
def test_no_summary(self):
"""
test when there is no summary section found
"""
# get the tasks for sas_id 54321
tasks_for_this_sasid = Task.objects.filter(sas_id=33333)
# 1 is enough, they all have the same summary_flavour
task = tasks_for_this_sasid[0]
summary_flavour = get_summary_flavour(task)
self.assertEqual(summary_flavour,None)
def test_default_summary_flavour(self):
"""
test if the DEFAULT summary_flavour is detected
"""
# get the tasks for sas_id 54321
tasks_for_this_sasid = Task.objects.filter(sas_id=54321)
# 1 is enough, they all have the same summary_flavour
task = tasks_for_this_sasid[0]
summary_flavour = get_summary_flavour(task)
self.assertEqual(summary_flavour,SummaryFlavour.DEFAULT.value)
def test_imaging_compression_summary_flavour(self):
"""
test if the IMAGING_COMPRESSION summary_flavour is detected
"""
tasks_for_this_sasid = Task.objects.filter(sas_id=55555)
# 1 is enough, they all have the same summary_flavour
task = tasks_for_this_sasid[0]
summary_flavour = get_summary_flavour(task)
self.assertEqual(summary_flavour,SummaryFlavour.IMAGING_COMPRESSION.value)
def test_link_calibrator_summary_flavour(self):
"""
test if the LINC_CALIBRATOR summary_flavour is detected
"""
tasks_for_this_sasid = Task.objects.filter(sas_id=666666)
# 1 is enough, they all have the same summary_flavour
task = tasks_for_this_sasid[0]
summary_flavour = get_summary_flavour(task)
self.assertEqual(summary_flavour,SummaryFlavour.LINC_CALIBRATOR.value)
def test_link_target_summary_flavour(self):
"""
test if the LINC_TARGET summary_flavour is detected
"""
tasks_for_this_sasid = Task.objects.filter(sas_id=666667)
# 1 is enough, they all have the same summary_flavour
task = tasks_for_this_sasid[0]
summary_flavour = get_summary_flavour(task)
self.assertEqual(summary_flavour,SummaryFlavour.LINC_TARGET.value)