diff --git a/Jenkinsfile b/Jenkinsfile index 6229cc90..a35ee305 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -42,6 +42,25 @@ pipeline { } } } + stage('DeployProdStack') { + agent { + label 'helm' + } + when { + buildingTag(); + } + steps { + script { + withKubeConfig([credentialsId: "prod-kube-config"]) { + sh('helm repo update && helm dependency update helm-chart/banzai/ '+ + '&& helm package helm-chart/banzai --app-version="${GIT_DESCRIPTION}" --version="${GIT_DESCRIPTION}" ' + + '&& helm upgrade --install banzai banzai-"${GIT_DESCRIPTION}".tgz --namespace=prod ' + + '--set image.tag="${GIT_DESCRIPTION}" --values=helm-chart/banzai/values-prod.yaml ' + + '--force --atomic --timeout=3600s') + } + } + } + } stage('DeployTestStack') { when { anyOf { diff --git a/banzai/dark.py b/banzai/dark.py index 3bb5f44b..dbd18469 100755 --- a/banzai/dark.py +++ b/banzai/dark.py @@ -1,5 +1,7 @@ import logging +import numpy as np + from banzai.stages import Stage from banzai.calibrations import CalibrationStacker, CalibrationUser, CalibrationComparer from banzai.utils import qc @@ -41,9 +43,14 @@ def calibration_type(self): def apply_master_calibration(self, image, master_calibration_image): master_calibration_image *= image.exptime + temperature_scaling_factor = np.exp(master_calibration_image.dark_temperature_coefficient * \ + (image.measured_ccd_temperature - master_calibration_image.measured_ccd_temperature)) + master_calibration_image *= temperature_scaling_factor + image -= master_calibration_image image.meta['L1IDDARK'] = master_calibration_image.filename, 'ID of dark frame' image.meta['L1STATDA'] = 1, 'Status flag for dark frame correction' + image.meta['DRKTSCAL'] = temperature_scaling_factor, 'Temperature scaling factor applied to dark image' return image diff --git a/banzai/lco.py b/banzai/lco.py index 3dba0328..a769000c 100644 --- a/banzai/lco.py +++ b/banzai/lco.py @@ -185,6 +185,10 @@ def is_master(self): def is_master(self, value): self.meta['ISMASTER'] = value + @property + def dark_temperature_coefficient(self): + return self.meta.get('DRKTCOEF', 0.0) + def write(self, runtime_context): output_products = LCOObservationFrame.write(self, runtime_context) CalibrationFrame.write(self, output_products, runtime_context) diff --git a/banzai/tests/test_dark_subtractor.py b/banzai/tests/test_dark_subtractor.py new file mode 100644 index 00000000..8286a579 --- /dev/null +++ b/banzai/tests/test_dark_subtractor.py @@ -0,0 +1,74 @@ +import pytest +import numpy as np +import mock + +from banzai.dark import DarkSubtractor +from banzai.tests.utils import FakeCCDData, FakeLCOObservationFrame, FakeContext +from banzai.lco import LCOCalibrationFrame +from banzai.data import CCDData + + +pytestmark = pytest.mark.dark_subtractor + + +@pytest.fixture(scope='module') +def set_random_seed(): + np.random.seed(7298374) + + +def test_null_input_images(): + normalizer = DarkSubtractor(None) + image = normalizer.run(None) + assert image is None + + +@mock.patch('banzai.lco.LCOFrameFactory.open') +@mock.patch('banzai.calibrations.CalibrationUser.get_calibration_file_info', return_value='test.fits') +def test_reasonable_dark_subtraction(mock_super_cal_name, mock_super_frame): + + mock_super_cal_name.return_value = {'filename': 'test.fits'} + mock_super_frame.return_value = LCOCalibrationFrame(hdu_list=[CCDData(data=0.5*np.ones((100,100)), + meta={'EXPTIME': 1.0, + 'SATURATE': 35000, + 'GAIN': 1.0, + 'MAXLIN': 35000, + 'ISMASTER': True, + 'CCDATEMP': -100})], file_path='/tmp') + image = FakeLCOObservationFrame(hdu_list=[CCDData(data=4*np.ones((100,100)), meta={'EXPTIME': 2.0, + 'SATURATE': 35000, + 'GAIN': 1.0, + 'MAXLIN': 35000, + 'CCDATEMP': -100})]) + subtractor = DarkSubtractor(FakeContext()) + image = subtractor.do_stage(image) + np.testing.assert_allclose(image.data, 3*np.ones((100,100))) + + +@mock.patch('banzai.lco.LCOFrameFactory.open') +@mock.patch('banzai.calibrations.CalibrationUser.get_calibration_file_info', return_value='test.fits') +def test_reasonable_dark_subtraction_with_scaling(mock_super_cal_name, mock_super_frame): + dark_temperature_coefficient = 0.5 + image_measured_temp = 0 + super_measured_temp = -5 + + mock_super_cal_name.return_value = {'filename': 'test.fits'} + mock_super_frame.return_value = LCOCalibrationFrame(hdu_list=[CCDData(data=0.5*np.ones((100,100)), + meta={'EXPTIME': 1.0, + 'SATURATE': 35000, + 'GAIN': 1.0, + 'MAXLIN': 35000, + 'ISMASTER': True, + 'DRKTCOEF': dark_temperature_coefficient, + 'CCDATEMP': -5})], file_path='/tmp') + image = FakeLCOObservationFrame(hdu_list=[CCDData(data=4*np.ones((100,100)), + meta={'EXPTIME': 2.0, + 'SATURATE': 35000, + 'GAIN': 1.0, + 'MAXLIN': 35000, + 'CCDATEMP': 0})]) + + dark_scaling_factor = np.exp(dark_temperature_coefficient * (image_measured_temp - super_measured_temp)) + subtracted_data = image.data - np.ones((100,100)) * dark_scaling_factor + subtractor = DarkSubtractor(FakeContext()) + image = subtractor.do_stage(image) + np.testing.assert_allclose(image.data, subtracted_data)