From c7b2befaf8b21f37ffe6bafa29d7216a3e2bcd89 Mon Sep 17 00:00:00 2001 From: Jonas Sinjan Date: Wed, 10 Nov 2021 14:35:44 +0100 Subject: [PATCH 01/34] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fea10a1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Jonas Sinjan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -- GitLab From e23547e5825e3687a2e2f82bf47b738f97215430 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 10:48:34 +0100 Subject: [PATCH 02/34] module import + field stop path fix --- README.md | 2 +- input_jsons/sep_2021_L1_north.json | 2 +- src/hrt_pipe.py | 4 ++-- src/hrt_pipe_sub.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8943781..032cac5 100755 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ source activate dataproc 5. Download files - see **DOWNLOAD INPUT FILES** Section -5. Genetate json files with the science, dark and flat you desire to reduce +5. Generate json files with the science, dark and flat you desire to reduce 6. Make sure the correct input.json file is being given to `hrt_pipe` in ```run.py``` diff --git a/input_jsons/sep_2021_L1_north.json b/input_jsons/sep_2021_L1_north.json index fde8afe..4f271bf 100644 --- a/input_jsons/sep_2021_L1_north.json +++ b/input_jsons/sep_2021_L1_north.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T034515_V202110211713C_0149140201.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/0169111100_DC_9data.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": false, "scale_data": true, "accum_scaling": true, "bit_conversion": true, "dark_c": true, "flat_c": true, "norm_f": true, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 24, "prefilter_f": null, "fs_c": true, "demod": true, "norm_stokes": true, "ItoQUV": false, "ctalk_params": null, "rte": "none", "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021/", "out_demod_file": true, "out_demod_filename": null, "out_rte_filename": null, "config_file": true} \ No newline at end of file +"/data/slam/home/sinjan/hrt_pipe_results/sep_2021_north/config_file_12_11_2021T10_46_54.json" \ No newline at end of file diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 486736c..97016db 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -10,8 +10,8 @@ import json import matplotlib.pyplot as plt from numpy.core.numeric import True_ -from .utils import * -from .hrt_pipe_sub import * +from utils import * +from hrt_pipe_sub import * def phihrt_pipe(input_json_file): diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 7578182..1003811 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -2,7 +2,7 @@ import numpy as np from astropy.io import fits from scipy.ndimage import gaussian_filter from operator import itemgetter -from .utils import * +from utils import * import os import time import subprocess @@ -348,7 +348,7 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - start_time = time.time() - field_stop,_ = load_fits('./field_stop/HRT_field_stop.fits') + field_stop,_ = load_fits('../field_stop/HRT_field_stop.fits') field_stop = np.where(field_stop > 0,1,0) -- GitLab From 01090a2918feb3204e05320b44b2700f6545c6e3 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 13:39:53 +0100 Subject: [PATCH 03/34] config fix --- src/hrt_pipe.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 97016db..410d53c 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -796,8 +796,7 @@ def phihrt_pipe(input_json_file): dt = datetime.datetime.fromtimestamp(overall_time) runtime = dt.strftime("%d_%m_%YT%H_%M_%S") - with open(input_json_file, "w+") as f: - json.dump(out_dir + f"config_file_{runtime}.json", f) + json.dump(input_dict, open(out_dir + f"config_file_{runtime}.json", "w")) print(" ") printc('--------------------------------------------------------------',color=bcolors.OKGREEN) -- GitLab From 635a14a8dbb967a987745efd2c14cd4d59f83551 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 13:46:47 +0100 Subject: [PATCH 04/34] fix on cmilos path --- src/hrt_pipe_sub.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 1003811..91d4b28 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -432,7 +432,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field try: CMILOS_LOC = os.path.realpath(__file__) - CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters + CMILOS_LOC = CMILOS_LOC[:-19] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters if os.path.isfile(CMILOS_LOC+'milos'): printc("Cmilos executable located at:", CMILOS_LOC,color=bcolors.WARNING) @@ -634,7 +634,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, try: CMILOS_LOC = os.path.realpath(__file__) - CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters + CMILOS_LOC = CMILOS_LOC[:-19] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters if os.path.isfile(CMILOS_LOC+'milos'): printc("Cmilos-fits executable located at:", CMILOS_LOC,color=bcolors.WARNING) -- GitLab From db3cc515557cb1c5b97e9fb26ffea3c699d0f29c Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 13:50:14 +0100 Subject: [PATCH 05/34] missed a typo --- src/hrt_pipe_sub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 91d4b28..3f52a6e 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -858,7 +858,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st try: PMILOS_LOC = os.path.realpath(__file__) - PMILOS_LOC = PMILOS_LOC[:-15] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py + PMILOS_LOC = PMILOS_LOC[:-19] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py if os.path.isfile(PMILOS_LOC+'pmilos.x'): printc("Pmilos executable located at:", PMILOS_LOC,color=bcolors.WARNING) -- GitLab From b373cc25bf952a0419b520e6af7e92f4967b2133 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 13:58:54 +0100 Subject: [PATCH 06/34] input json fix --- .gitignore | 4 +- input_jsons/sep_2021_L1_south_noflat.json | 2 +- input_jsons/sep_2021_L1_west.json | 2 +- test/test_jsons/create_input_json.py | 218 ++++++++++++++++++++++ 4 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 test/test_jsons/create_input_json.py diff --git a/.gitignore b/.gitignore index b51dfd6..1a40057 100755 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,6 @@ input_jsons/feb_2k_2021_L1.txt input_jsons/nov_2020_L1_feb_flats.txt input_jsons/nov_2020_L1.txt src/create_input_json.py -*.pyc \ No newline at end of file +*.pyc +input_jsons/sep_2021_L1_west.json +input_jsons/sep_2021_L1_south_noflat.json diff --git a/input_jsons/sep_2021_L1_south_noflat.json b/input_jsons/sep_2021_L1_south_noflat.json index a5839b6..7a16804 100644 --- a/input_jsons/sep_2021_L1_south_noflat.json +++ b/input_jsons/sep_2021_L1_south_noflat.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T053015_V202110150939C_0149140301.fits", "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T053445_V202110150939C_0149140302.fits", "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T053909_V202110150939C_0149140303.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/0169111100_DC_9data.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": false, "L1_8_generate": false, "scale_data": true, "accum_scaling": true, "bit_conversion": true, "dark_c": true, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 24, "prefilter_f": null, "fs_c": true, "limb": "S", "demod": true, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": "none", "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_south_no_flat/", "out_stokes_file": true, "out_stokes_filename": null, "out_rte_filename": null, "config_file": false} \ No newline at end of file +"/data/slam/home/sinjan/hrt_pipe_results/sep_2021_south/config_file_12_11_2021T11_00_13.json" \ No newline at end of file diff --git a/input_jsons/sep_2021_L1_west.json b/input_jsons/sep_2021_L1_west.json index a5c8721..e9e2451 100644 --- a/input_jsons/sep_2021_L1_west.json +++ b/input_jsons/sep_2021_L1_west.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits", "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071945_V202110260809C_0149140402.fits", "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T072409_V202110260809C_0149140403.fits", "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T072833_V202110260809C_0149140404.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/0169111100_DC_9data.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": false, "scale_data": true, "accum_scaling": true, "bit_conversion": true, "dark_c": true, "flat_c": true, "norm_f": true, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 24, "prefilter_f": null, "fs_c": true, "demod": true, "norm_stokes": true, "ItoQUV": false, "ctalk_params": null, "rte": "none", "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021/", "out_demod_file": true, "out_demod_filename": null, "out_rte_filename": null, "config_file": true} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/0169111100_DC_9data.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": false, "L1_8_generate": false, "scale_data": true, "accum_scaling": true, "bit_conversion": true, "dark_c": true, "flat_c": true, "norm_f": true, "clean_f": true, "sigma": 59, "clean_mode": "UV", "flat_states": 24, "prefilter_f": null, "fs_c": true, "limb": "W", "demod": true, "norm_stokes": true, "ItoQUV": false, "ctalk_params": null, "rte": "RTE", "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_west_us_check/", "out_stokes_file": true, "out_stokes_filename": null, "out_rte_filename": null, "config": true} \ No newline at end of file diff --git a/test/test_jsons/create_input_json.py b/test/test_jsons/create_input_json.py new file mode 100644 index 0000000..011362d --- /dev/null +++ b/test/test_jsons/create_input_json.py @@ -0,0 +1,218 @@ +import json +import numpy as np + + + +""" +#April 2020 L1 + +# CAN also do the L1 files - but must set bit_convert_scale to false, and scale data to False for the flat fields, and presumably same for the input data + +science_april = ['solo_L1_phi-hrt-ilam_20200420T141802_V202107221036C_0024160030.fits', +'solo_L1_phi-hrt-ilam_20200420T142032_V202107221036C_0024160031.fits', +'solo_L1_phi-hrt-ilam_20200420T142302_V202107221036C_0024160032.fits', +'solo_L1_phi-hrt-ilam_20200420T142532_V202107221037C_0024160033.fits', +'solo_L1_phi-hrt-ilam_20200420T142803_V202107221037C_0024160034.fits', +'solo_L1_phi-hrt-ilam_20200420T143033_V202107221037C_0024160035.fits', +'solo_L1_phi-hrt-ilam_20200420T143303_V202107221037C_0024160036.fits', +'solo_L1_phi-hrt-ilam_20200420T143533_V202107221037C_0024160037.fits', +'solo_L1_phi-hrt-ilam_20200420T143803_V202107221037C_0024160038.fits', +'solo_L1_phi-hrt-ilam_20200420T144033_V202107221038C_0024160039.fits'] + +flatfield_fits_filename = '/data/slam/home/sinjan/fits_files/april_avgd_2020_flat.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +darkfield_fits_filename = '../fits_files/solo_L0_phi-fdt-ilam_20200228T155100_V202002281636_0022210004_000.fits' + +science_april = ['/data/slam/home/sinjan/fits_files/' + i for i in science_april] + +input_dict = { + 'data_f': science_april, + 'flat_f' : flatfield_fits_filename, + 'dark_f' : darkfield_fits_filename +} + +json.dump(input_dict, open(f"./input_jsons/april_2020_L1.txt", "w")) +""" + +""" +#Nov 17 2020 L1 + +# CAN also do the L1 files - but must set bit_convert_scale to false, and scale data to False for the flat fields, and presumably same for the input data + +science_nov = ['solo_L1_phi-hrt-ilam_20201117T170209_V202108301639C_0051170001.fits']#['solo_L1_phi-hrt-ilam_20201117T170209_V202107060747C_0051170001.fits'] + +flatfield_fits_filename = '/data/slam/home/sinjan/fits_files/april_avgd_2020_flat.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +darkfield_fits_filename = '../fits_files/solo_L0_phi-fdt-ilam_20200228T155100_V202002281636_0022210004_000.fits' + +science_nov = ['/data/slam/home/sinjan/fits_files/' + i for i in science_nov] + +input_dict = { + 'data_f': science_nov, + 'flat_f' : flatfield_fits_filename, + 'dark_f' : darkfield_fits_filename +} + +json.dump(input_dict, open(f"./input_jsons/nov_2020_L1.txt", "w")) +""" + + +""" +#Nov 17 2020 L1 Feb Flats + +# CAN also do the L1 files - but must set bit_convert_scale to false, and scale data to False for the flat fields, and presumably same for the input data + +science_nov = ['solo_L1_phi-hrt-ilam_20201117T170209_V202107060747C_0051170001.fits'] + +flatfield_fits_filename = '/data/slam/home/sinjan/fits_files/solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +darkfield_fits_filename = '../fits_files/solo_L0_phi-fdt-ilam_20200228T155100_V202002281636_0022210004_000.fits' + +science_nov = ['/data/slam/home/sinjan/fits_files/' + i for i in science_nov] + +input_dict = { + 'data_f': science_nov, + 'flat_f' : flatfield_fits_filename, + 'dark_f' : darkfield_fits_filename +} + +json.dump(input_dict, open(f"./input_jsons/nov_2020_L1_feb_flats.txt", "w")) +""" + +""" +#Nov 17 2020 L1 KLL flats + +# CAN also do the L1 files - but must set bit_convert_scale to false, and scale data to False for the flat fields, and presumably same for the input data + +science_nov = ['solo_L1_phi-hrt-ilam_20201117T170209_V202107060747C_0051170001.fits'] + +flatfield_fits_filename = '/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-flat_20210321T210847_V202108301617C_0163211100.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +darkfield_fits_filename = '../fits_files/solo_L0_phi-fdt-ilam_20200228T155100_V202002281636_0022210004_000.fits' + +science_nov = ['/data/slam/home/sinjan/fits_files/' + i for i in science_nov] + +input_dict = { + 'data_f': science_nov, + 'flat_f' : flatfield_fits_filename, + 'dark_f' : darkfield_fits_filename +} + +json.dump(input_dict, open(f"./input_jsons/nov_2020_L1_kll.txt", "w")) + +""" + + +""" +#Feb 2021 L1 + + +science_feb = ['solo_L1_phi-hrt-ilam_20210223T170002_V202107221048C_0142230201.fits'] + +flatfield_fits_filename = '/data/slam/home/sinjan/fits_files/solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +darkfield_fits_filename = '../fits_files/solo_L0_phi-fdt-ilam_20200228T155100_V202002281636_0022210004_000.fits' + +science_feb = ['/data/slam/home/sinjan/fits_files/' + i for i in science_feb] + +input_dict = { + 'data_f': science_feb, + 'flat_f' : flatfield_fits_filename, + 'dark_f' : darkfield_fits_filename +} + +json.dump(input_dict, open(f"./input_jsons/feb_2k_2021_L1.txt", "w")) + +""" + +""" +#Sep 2021 data + +science_sep = ['solo_L1_phi-hrt-ilam_20210914T053015_V202110150939C_0149140301.fits']#['solo_L1_phi-hrt-ilam_20210914T034515_V202110211713C_0149140201.fits'] + +flat = '/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +dark = '/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits' + +science_nov = ['/data/slam/home/sinjan/fits_files/' + i for i in science_sep] + +input_dict = { + 'data_f': science_nov, + 'flat_f' : flat, + 'dark_f' : dark +} + +json.dump(input_dict, open(f"./input_jsons/sep_2021_L1_sl.txt", "w")) + +""" + +science = ['solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits'] + +flat = '/data/slam/home/sinjan/fits_files/0169111100_DC_9data.fits'#solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits' #solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + +dark = '/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits' + +science_2 = ['/data/slam/home/sinjan/fits_files/' + i for i in science] + + +""" +c_talk_params = np.zeros((2,3)) + +q_slope = -0.0263#0.0038#-0.0140##-0.0098# +u_slope = 0.0023#-0.0077#-0.0008##-0.0003# +v_slope = -0.0116#-0.0009#-0.0073##-0.0070# + +q_int = 0.0138#-0.0056#0.0016#-0.0056#-0.0015# #the offset, normalised to I_c +u_int = -0.0016#0.0031#0.0016##0.0007# +v_int = 0.0057#-0.0002#0.0007##0.0006# + +c_talk_params[0,0] = q_slope +c_talk_params[0,1] = u_slope +c_talk_params[0,2] = v_slope + +c_talk_params[1,0] = q_int +c_talk_params[1,1] = u_int +c_talk_params[1,2] = v_int +""" + + +input_dict = { + #input data + 'data_f': science_2, + 'flat_f' : flat, + 'dark_f' : dark, + + #input/output type + scaling + 'L1_input' : False, + 'L1_8_generate': False, #not developed yet + 'scale_data' : True, #these 3 will be made redundant once L1 data scaling is normalised - needed mainly for comissioning (IP5) data + 'accum_scaling' : True, + 'bit_conversion' : True, + + #reduction + 'dark_c' : True, + 'flat_c' : True, + 'norm_f' : True, + 'clean_f' : False, + 'sigma' : 59, #unsharp masking gaussian width + 'clean_mode' : "UV", #options 'QUV', 'UV', 'V' for the unsharp masking + 'flat_states' : 24, #options 4 (one each pol state), 6 (one each wavelength), 24 + 'prefilter_f': None, + 'fs_c' : True, + 'limb' : 'W', #specify if it is a limb observation, options are 'N', 'S', 'W', 'E' + 'demod' : False, + 'norm_stokes' : False, + 'ItoQUV' : False, #missing VtoQU - not developed yet + 'ctalk_params' : None, #VtoQU parameters will be required in this argument once ready + 'rte' : None, #options: ''RTE', 'CE', 'CE+RTE' + 'p_milos' : False, #attempted, ran into problems - on hold + 'cmilos_fits_opt': False, #whether to use cmilos-fits + + #output dir/filenames + 'out_dir' : '/data/slam/home/sinjan/hrt_pipe_tests/', + 'out_stokes_file' : False, #if True, will save stokes array to fits, the array that is fed into the RTE inversions + 'out_stokes_filename' : None, #if specific and not default name + 'out_rte_filename' : None, #if specific and not default name +} + +json.dump(input_dict, open(f"./dark_flat_test_apr_2020.json", "w")) \ No newline at end of file -- GitLab From 0ab2fc08bb89c49851cd8f4f0f0fbc78de8f4e4c Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 12 Nov 2021 15:30:39 +0100 Subject: [PATCH 07/34] rename variables --- src/hrt_pipe.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 410d53c..ecc2719 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -142,7 +142,7 @@ def phihrt_pipe(input_json_file): limb = input_dict['limb'] demod = input_dict['demod'] norm_stokes = input_dict['norm_stokes'] - CT_ItoQUV = input_dict['ItoQUV'] + ItoQUV = input_dict['ItoQUV'] ctalk_params = input_dict['ctalk_params'] rte = input_dict['rte'] p_milos = input_dict['p_milos'] @@ -328,8 +328,6 @@ def phihrt_pipe(input_json_file): flat_copy = flat.copy() flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) -# flat[1345, 296:, 1, 1] = flat_copy[1344, 296:, 1, 1] -# flat[1346, :291, 1, 1] = flat_copy[1345, :291, 1, 1] del flat_copy printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -575,7 +573,7 @@ def phihrt_pipe(input_json_file): Ic_mask = np.array(Ic_mask, dtype=bool) I_c = np.mean(data[Ic_mask,0,cpos_arr[0],int(scan)]) - data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c + data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c # if out_intermediate: # data_demod = data.copy() @@ -592,7 +590,7 @@ def phihrt_pipe(input_json_file): # CROSS-TALK CALCULATION #----------------- - if CT_ItoQUV: + if ItoQUV: print(" ") printc('-->>>>>>> Cross-talk correction I to Q,U,V ',color=bcolors.OKGREEN) @@ -623,9 +621,8 @@ def phihrt_pipe(input_json_file): ctalk_params = np.repeat(ctalk_params[:,:,np.newaxis], num_of_scans, axis = 2) - try: - data = CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask) + data = CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask) except Exception: print("There was an issue applying the I -> Q,U,V cross talk correction") if 'Ic_mask' not in vars(): -- GitLab From add6a0ee51e4b36d01cbc4aabb31ec9f1d91b592 Mon Sep 17 00:00:00 2001 From: dcalc <35452781+dcalc@users.noreply.github.com> Date: Fri, 12 Nov 2021 15:44:31 +0100 Subject: [PATCH 08/34] new auto CT --- hrt_pipe.py | 817 ++++++++++++++++++++++++++++++++++ hrt_pipe_sub.py | 1121 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1938 insertions(+) create mode 100644 hrt_pipe.py create mode 100644 hrt_pipe_sub.py diff --git a/hrt_pipe.py b/hrt_pipe.py new file mode 100644 index 0000000..e5d7a7b --- /dev/null +++ b/hrt_pipe.py @@ -0,0 +1,817 @@ +from posix import listdir +import numpy as np +import os.path +from astropy.io import fits +# from scipy.ndimage import gaussian_filter +import time +import datetime +from operator import itemgetter +import json +import matplotlib.pyplot as plt +from numpy.core.numeric import True_ + +from utils import * +from hrt_pipe_sub import * + + +def phihrt_pipe(input_json_file): + + ''' + PHI-HRT data reduction pipeline + 1. read in science data (+ OPTION: scaling) open path option + open for several scans at once + 2. read in flat field (+scaling)- just accepts one flat field fits file + 3. read in dark field (+scaling) + 4. apply dark field + 5. option to clean flat field with unsharp masking + 6. normalise flat field + 7. apply flat field + 8. apply prefilter + 9. read in field stop + 10. apply field stop + 11. demodulate with const demod matrix + a) option to output demod to fits file + 12. normalise to quiet sun + 13. calibration + a) ghost correction - not implemented yet + b) cross talk correction + 14. rte inversion with pmilos/cmilos (CE, RTE or CE+RTE) + a) output rte data products to fits file + + Parameters + ---------- + Input: + data_f : list or string + list containing paths to fits files of the raw HRT data OR string of path to one file - must have last 10 characters before .fits as the DID - for naming purposes of output files + dark_f : string, DEFAULT '' + Fits file of a dark file (ONLY ONE FILE) + flat_f : string, DEFAULT '' + Fits file of a HRT flatfield (ONLY ONE FILE) + + ** Options: + L1_input: bool, DEFAULT True + ovverides scale_data, bit_conversion, and accum_scaling, so that correct scaling for L1 data applied + L1_8_generate: bool, DEFAULT False + if True, assumes L1 input, and generates RTE output with the calibration header information + scale_data: bool, DEFAULT True + performs the accumulation scaling + conversion for flat and science (only FALSE for commissioning data) + bit_conversion: bool, DEFAULT True + divides the scan + flat by 256 to convert from 24.8bit to 32bits + norm_f: bool, DEFAULT: True + to normalise the flat fields before applying + clean_f: str, DEFAULT: None + clean the flat field with unsharp masking, accepted values = ['blurring','fft'] + sigma: int, DEFAULT: 59 + sigma of the gaussian convolution used for unsharp masking if clean_f == 'blurring', 'fft' + clean_mode: str, DEFAULT: "V" + The polarisation states of the flat field to be unsharp masked, options are "V", "UV" and "QUV" + flat_states: int, DEFAULT: 24 + Number of flat fields to be applied, options are 4 (one for each pol state), 6 (one for each wavelength), 24 (one for each image) + prefilter_f: str, DEFAULT None + file path location to prefilter fits file, apply prefilter correction + flat_c: bool, DEFAULT: True + apply flat field correction + dark_c: bool, DEFAULT: True + apply dark field correction + fs_c: bool, DEFAULT True + apply HRT field stop + limb: str, DEFAULT None + specify if it is a limb observation, options are 'N', 'S', 'W', 'E' + demod: bool, DEFAULT: True + apply demodulate to the stokes + norm_stokes: bool, DEFAULT: True + normalise the stokes vector to the quiet sun (I_continuum) + out_dir : string, DEFUALT: './' + directory for the output files + out_stokes_file: bool, DEFAULT: False + output file with the stokes vectors to fits file + out_stokes_filename: str, DEFAULT = None + if None, takes last 10 characters of input scan filename (assumes its a DID), change if want other name + ItoQUV: bool, DEFAULT: False + apply I -> Q,U,V correction + ctalk_params: numpy arr, DEFAULT: None + cross talk parameters for ItoQUV, (2,3) numpy array required: first axis: Slope, Offset (Normalised to I_c) - second axis: Q,U,V + rte: str, DEFAULT: False + invert using cmilos, options: 'RTE' for Milne Eddington Inversion, 'CE' for Classical Estimates, 'CE+RTE' for combined + out_rte_filename: str, DEFAULT = '' + if '', takes last 10 characters of input scan filename (assumes its a DID), change if want other name + p_milos: bool, DEFAULT = True + if True, will execute the RTE inversion using the parallel version of the CMILOS code on 16 processors + Returns + ------- + data: numpy array + stokes vector + flat: numpy array + flat field + + References + ---------- + SPGYlib + + ''' + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc('PHI HRT data reduction software ',bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + #----------------- + # READ INPUT JSON + #----------------- + + input_dict = json.load(open(input_json_file)) + + try: + data_f = input_dict['data_f'] + flat_f = input_dict['flat_f'] + dark_f = input_dict['dark_f'] + + L1_input = input_dict['L1_input'] + L1_8_generate = input_dict['L1_8_generate'] + scale_data = input_dict['scale_data'] + accum_scaling = input_dict['accum_scaling'] + bit_conversion = input_dict['bit_conversion'] + + dark_c = input_dict['dark_c'] + flat_c = input_dict['flat_c'] + norm_f = input_dict['norm_f'] + clean_f = input_dict['clean_f'] + sigma = input_dict['sigma'] + clean_mode = input_dict['clean_mode'] + flat_states = input_dict['flat_states'] + prefilter_f = input_dict['prefilter_f'] + fs_c = input_dict['fs_c'] + limb = input_dict['limb'] + demod = input_dict['demod'] + norm_stokes = input_dict['norm_stokes'] + ItoQUV = input_dict['ItoQUV'] +# ctalk_params = input_dict['ctalk_params'] + rte = input_dict['rte'] + p_milos = input_dict['p_milos'] + cmilos_fits_opt = input_dict['cmilos_fits_opt'] + + out_dir = input_dict['out_dir'] + out_stokes_file = input_dict['out_stokes_file'] + out_stokes_filename = input_dict['out_stokes_filename'] + out_rte_filename = input_dict['out_rte_filename'] + + if 'config' not in input_dict: + config = True + else: + config = input_dict['config'] + + except Exception as e: + print(f"Missing key(s) in the input config file: {e}") + raise KeyError + + overall_time = time.time() + + if L1_input: + print("L1_input param set to True - Assuming L1 science data") + accum_scaling = True + bit_conversion = True + scale_data = True + + #----------------- + # READ DATA + #----------------- + + print(" ") + printc('-->>>>>>> Reading Data',color=bcolors.OKGREEN) + + start_time = time.time() + + if isinstance(data_f, str): + data_f = [data_f] + + if isinstance(data_f, list): + #if the data_f contains several scans + printc(f'Input contains {len(data_f)} scan(s)',color=bcolors.OKGREEN) + + number_of_scans = len(data_f) + + data_arr = [0]*number_of_scans + hdr_arr = [0]*number_of_scans + + wve_axis_arr = [0]*number_of_scans + cpos_arr = [0]*number_of_scans + voltagesData_arr = [0]*number_of_scans + tuning_constant_arr = [0]*number_of_scans + + for scan in range(number_of_scans): + data_arr[scan], hdr_arr[scan] = get_data(data_f[scan], scaling = accum_scaling, bit_convert_scale = bit_conversion, scale_data = scale_data) + + wve_axis_arr[scan], voltagesData_arr[scan], tuning_constant_arr[scan], cpos_arr[scan] = fits_get_sampling(data_f[scan],verbose = True) + + if 'IMGDIRX' in hdr_arr[scan] and hdr_arr[scan]['IMGDIRX'] == 'YES': + print(f"This scan has been flipped in the Y axis to conform to orientation standards. \n File: {data_f[scan]}") + + #-------- + # test if the scans have different sizes + #-------- + + check_size(data_arr) + + #-------- + # test if the scans have different continuum wavelength_positions + #-------- + + check_cpos(cpos_arr) + + #-------- + # test if the scans have different pmp temperatures + #-------- + + pmp_temp = check_pmp_temp(hdr_arr) + + #so that data is [y,x,24,scans] + data = np.stack(data_arr, axis = -1) + data = np.moveaxis(data, 0,-2) + + print(f"Data shape is {data.shape}") + + #-------- + # test if the scans have same IMGDIRX keyword + #-------- + + header_imgdirx_exists, imgdirx_flipped = check_IMGDIRX(hdr_arr) + + else: + printc("ERROR, data_f argument is neither a string nor list containing strings: {} \n Ending Process",data_f,color=bcolors.FAIL) + exit() + + data_shape = data.shape + + data_size = data_shape[:2] + + #converting to [y,x,pol,wv,scans] + + data = stokes_reshape(data) + + #enabling cropped datasets, so that the correct regions of the dark field and flat field are applied + print("Data reshaped to: ", data.shape) + + diff = 2048-data_size[0] #handling 0/2 errors + + if np.abs(diff) > 0: + + start_row = int((2048-data_size[0])/2) + start_col = int((2048-data_size[1])/2) + + else: + start_row, start_col = 0, 0 + + rows = slice(start_row,start_row + data_size[0]) + cols = slice(start_col,start_col + data_size[1]) + ceny = slice(data_size[0]//2 - data_size[0]//4, data_size[0]//2 + data_size[0]//4) + cenx = slice(data_size[1]//2 - data_size[1]//4, data_size[1]//2 + data_size[1]//4) + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load science data time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + + #----------------- + # READ FLAT FIELDS + #----------------- + + if flat_c: + print(" ") + printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) + + start_time = time.time() + + # flat from IP-5 + if '0024151020000' in flat_f or '0024150020000' in flat_f: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=False) + else: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=scale_data) + + if 'IMGDIRX' in header_flat: + header_fltdirx_exists = True + fltdirx_flipped = str(header_flat['IMGDIRX']) + else: + header_fltdirx_exists = False + fltdirx_flipped = 'NO' + + print(f"Flat field shape is {flat.shape}") + # correction based on science data - see if flat and science are both flipped or not + flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) + + flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] + flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states + flat = np.moveaxis(flat, 2,-1) + + print(flat.shape) + + _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position + + print(f"The continuum position of the flat field is at {cpos_f} index position") + + #-------- + # test if the science and flat have continuum at same position + #-------- + + flat = compare_cpos(flat,cpos_f,cpos_arr[0]) + + flat_pmp_temp = str(header_flat['HPMPTSP1']) + + print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") + + + #-------- + # correct for missing line in particular flat field + #-------- + + if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + print("This flat has a missing line - filling in with neighbouring pixels") + flat_copy = flat.copy() + flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) + +# flat[1345, 296:, 1, 1] = flat_copy[1344, 296:, 1, 1] +# flat[1346, :291, 1, 1] = flat_copy[1345, :291, 1, 1] + del flat_copy + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + + else: + print(" ") + printc('-->>>>>>> No flats mode',color=bcolors.WARNING) + + + #----------------- + # READ AND CORRECT DARK FIELD + #----------------- + + if dark_c: + print(" ") + printc('-->>>>>>> Reading Darks ',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + + if dark_f[-19:] != '0022210004_000.fits': + dark,h = get_data(dark_f,scaling = accum_scaling, bit_convert_scale = bit_conversion,scale_data = scale_data) + else: + dark,h = get_data(dark_f, scaling = accum_scaling, bit_convert_scale = bit_conversion, scale_data = False) + + dark_shape = dark.shape + if dark_shape != (2048,2048): + + printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) + printc("Attempting to correct ",color=bcolors.WARNING) + + try: + if dark_shape[0] > 2048: + dark = dark[dark_shape[0]-2048:,:] + + except Exception: + printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) + # DC change 20211018 + if 'IMGDIRX' in h: + header_drkdirx_exists = True + drkdirx_flipped = str(h['IMGDIRX']) + else: + header_drkdirx_exists = False + drkdirx_flipped = 'NO' + + dark = compare_IMGDIRX(dark[np.newaxis],header_imgdirx_exists,imgdirx_flipped,header_drkdirx_exists,drkdirx_flipped)[0] + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + except Exception: + printc("ERROR, Unable to open darks file: {}",dark_f,color=bcolors.FAIL) + raise ValueError() + + #----------------- + # APPLY DARK CORRECTION + #----------------- + + if flat_c == False: + flat = np.empty((2048,2048,4,6)) + + data, flat = apply_dark_correction(data, flat, dark, rows, cols) + + if flat_c == False: + flat = np.empty((2048,2048,4,6)) + + # if out_intermediate: + # data_darkc = data.copy() + + else: + print(" ") + printc('-->>>>>>> No dark mode',color=bcolors.WARNING) + + + #----------------- + # OPTIONAL Unsharp Masking clean the flat field stokes Q, U or V images + #----------------- + + if clean_f is not None and flat_c: + print(" ") + printc('-->>>>>>> Cleaning flats with Unsharp Masking',color=bcolors.OKGREEN) + + start_time = time.time() + + flat = unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode, clean_f = "blurring") + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Cleaning flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + else: + print(" ") + printc('-->>>>>>> No clean flats mode',color=bcolors.WARNING) + + + #----------------- + # NORM FLAT FIELDS + #----------------- + + if norm_f and flat_c: + + flat = normalise_flat(flat, flat_f, ceny, cenx) + + else: + print(" ") + printc('-->>>>>>> No normalising flats mode',color=bcolors.WARNING) + + + #----------------- + # APPLY FLAT CORRECTION + #----------------- + + if flat_c: + try: + data = flat_correction(data,flat,flat_states,rows,cols) + + # if out_intermediate: + # data_flatc = data.copy() + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + except: + printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) + + else: + print(" ") + printc('-->>>>>>> No flat field correction mode',color=bcolors.WARNING) + + + #----------------- + # PREFILTER CORRECTION + #----------------- + + if prefilter_f is not None: + print(" ") + printc('-->>>>>>> Prefilter Correction',color=bcolors.OKGREEN) + + start_time = time.time() + + prefilter_voltages = [-1300.00,-1234.53,-1169.06,-1103.59,-1038.12,-972.644,-907.173,-841.702,-776.231,-710.760,-645.289, + -579.818,-514.347,-448.876,-383.404,-317.933,-252.462,-186.991,-121.520,-56.0490,9.42212,74.8932, + 140.364,205.835,271.307, 336.778,402.249,467.720,533.191,598.662,664.133,729.604,795.075,860.547, + 926.018,991.489,1056.96,1122.43,1187.90,1253.37, 1318.84,1384.32,1449.79,1515.26,1580.73,1646.20, + 1711.67,1777.14,1842.61] + + prefilter, _ = load_fits(prefilter_f) + + #prefilter = prefilter[:,652:1419,613:1380] #crop the helioseismology data + + data = prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages) + + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Prefilter correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + else: + print(" ") + printc('-->>>>>>> No prefilter mode',color=bcolors.WARNING) + + + #----------------- + # FIELD STOP + #----------------- + + if fs_c: + data, field_stop = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) + + + else: + print(" ") + printc('-->>>>>>> No field stop mode',color=bcolors.WARNING) + + + #----------------- + # APPLY DEMODULATION + #----------------- + + if demod: + + print(" ") + printc('-->>>>>>> Demodulating data',color=bcolors.OKGREEN) + + start_time = time.time() + + data,_ = demod_hrt(data, pmp_temp) + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Demodulation time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + else: + print(" ") + printc('-->>>>>>> No demod mode',color=bcolors.WARNING) + + + #----------------- + # APPLY NORMALIZATION + #----------------- + + if norm_stokes: + + print(" ") + printc('-->>>>>>> Normalising Stokes to Quiet Sun',color=bcolors.OKGREEN) + + start_time = time.time() + + Ic_mask = np.zeros((data_size[0],data_size[1],data_shape[-1]),dtype=bool) + I_c = np.ones(data_shape[-1]) + if limb is not None: + limb_mask = np.zeros((data_size[0],data_size[1],data_shape[-1])) + + for scan in range(data_shape[-1]): + + #I_c = np.mean(data[ceny,cenx,0,cpos_arr[0],int(scan)]) #mean of central 1k x 1k of continuum stokes I + #I_c = np.mean(data[50:500,700:1700,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun north limb + #I_c = np.mean(data[1500:2000,800:1300,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun south limb + #I_c = np.mean(data[350:1700,200:900,0,cpos_arr[0],int(scan)]) # West limb + limb_copy = np.copy(data) + + #from Daniele Calchetti + + if limb is not None: + if limb == 'N': + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = True) + if limb == 'S': + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = False) + if limb == 'W': + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = True) + if limb == 'E': + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = False) + + limb_temp = np.where(limb_temp>0,1,0) + Ic_temp = np.where(Ic_temp>0,1,0) + + data[:,:,:,:,scan] = data[:,:,:,:,scan] * limb_temp[:,:,np.newaxis,np.newaxis] + limb_mask[...,scan] = limb_temp + else: + Ic_temp = np.zeros(data_size) + Ic_temp[ceny,cenx] = 1 + Ic_temp = np.where(Ic_temp>0,1,0) + + if fs_c: + Ic_temp *= field_stop + + Ic_temp = np.array(Ic_temp, dtype=bool) + Ic_mask[...,scan] = Ic_temp + I_c[scan] = np.mean(data[Ic_temp,0,cpos_arr[0],int(scan)]) + data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c[scan] + + # if out_intermediate: + # data_demod = data.copy() + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Stokes Normalising time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + else: + print(" ") + printc('-->>>>>>> No normalising Stokes mode',color=bcolors.WARNING) + + + #----------------- + # CROSS-TALK CALCULATION + #----------------- + + if ItoQUV: + + print(" ") + printc('-->>>>>>> Cross-talk correction I to Q,U,V ',color=bcolors.OKGREEN) + + start_time = time.time() + + num_of_scans = data_shape[-1] + + slope, offset = 0, 1 + q, u, v = 0, 1, 2 + CTparams = np.zeros((2,3,number_of_scans)) + + for scan, scan_hdr in enumerate(hdr_arr): + printc(f' ---- >>>>> CT parameters computation of data scan number: {scan} .... ',color=bcolors.OKGREEN) + ctalk_params = crosstalk_auto_ItoQUV(data[...,scan],cpos_arr[scan],0,roi=Ic_mask[...,scan]) + CTparams[...,scan] = ctalk_params + + if 'CAL_CRT0' in scan_hdr: #check to make sure the keywords exist + + scan_hdr['CAL_CRT0'] = round(ctalk_params[slope,q],4) #I-Q slope + scan_hdr['CAL_CRT2'] = round(ctalk_params[slope,u],4) #I-U slope + scan_hdr['CAL_CRT4'] = round(ctalk_params[slope,v],4) #I-V slope + + scan_hdr['CAL_CRT1'] = round(ctalk_params[offset,q],4) #I-Q offset + scan_hdr['CAL_CRT3'] = round(ctalk_params[offset,u],4) #I-U offset + scan_hdr['CAL_CRT5'] = round(ctalk_params[offset,v],4) #I-V offset + + try: + data = CT_ItoQUV(data, CTparams, norm_stokes, cpos_arr, Ic_mask) + except Exception: + print("There was an issue applying the I -> Q,U,V cross talk correction") + if 'Ic_mask' not in vars(): + print("This could be because 'norm_f' was not set to True") + if data.shape[:2] == (2048,2048): + response = input("The input data is 2k x 2k \n Are all the input data files disk centre pointing? [y/n]") + if response == 'y' or response == 'Y': + try: + Ic_mask = np.zeros(data_size) + Ic_mask[ceny,cenx] = 1 + Ic_mask = np.where(Ic_mask>0,1,0) + Ic_mask = np.array(Ic_mask, dtype = bool) + data = CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask) + except Exception: + print("The issue could not be overcome\n Please check the input config file\n Aborting") + exit() + else: + raise KeyError("Response was not 'y' or 'Y'\n 'norm_f' keyword in input config file not set to True\n Aborting") + else: + raise KeyError("The issue could not be overcome as the Input data is not 2k x 2k\n 'norm_f' keyword in input config file not set to True\n Aborting") + else: + raise KeyError("'norm_f' keyword in input config file not set to True \n Aborting") + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- I -> Q,U,V cross talk correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + data *= field_stop[rows,cols, np.newaxis, np.newaxis, np.newaxis] + # DC change 20211019 only for limb + if limb is not None: + data *= limb_mask[rows,cols, np.newaxis, np.newaxis] + + else: + print(" ") + printc('-->>>>>>> No ItoQUV mode',color=bcolors.WARNING) + + + #----------------- + #CHECK FOR INFs + #----------------- + + data[np.isinf(data)] = 0 + data[np.isnan(data)] = 0 + + + #----------------- + #WRITE OUT STOKES VECTOR + #----------------- + + #these two ifs need to be outside out_stokes_file if statement - needed for inversion + if out_dir[-1] != "/": + print("Desired Output directory missing / character, will be added") + out_dir = out_dir + "/" + + #check if the output directory exists, if not, create it + if not os.path.exists(out_dir): + print(f"{out_dir} does not exist -->>>>>>> Creating it") + os.makedirs(out_dir) + + + if out_stokes_file: + + print(" ") + printc('Saving demodulated data to one _reduced.fits file per scan') + + if out_stokes_filename is not None: + + if isinstance(out_stokes_filename,str): + out_stokes_filename = [out_stokes_filename] + + if int(len(out_stokes_filename)) == int(data_shape[-1]): + scan_name_list = out_stokes_filename + scan_name_defined = True + else: + print("Input demod filenames do not match the number of input arrays, reverting to default naming") + scan_name_defined = False + else: + scan_name_defined = False + + if not scan_name_defined: #check if already defined by input, otherwise generate + scan_name_list = check_filenames(data_f) + + + for count, scan in enumerate(data_f): + + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_reduced.fits") + hdu_list[0].data = data[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_reduced.fits', overwrite=True) + + # DC change 20211014 + """ + if out_intermediate: + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_dark_corrected.fits") + hdu_list[0].data = data_darkc[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_dark_corrected.fits', overwrite=True) + + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") + hdu_list[0].data = data_flatc[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) + + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_demodulated.fits") + hdu_list[0].data = data_demod[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) + """ + + # with fits.open(scan) as hdu_list: + # hdu_list[0].data = limb_copy + # hdu_list.writeto(out_dir+scan_name_list[count]+'_limb_fit_input.fits', overwrite=True) + + else: + print(" ") + #check if already defined by input, otherwise generate + scan_name_list = check_filenames(data_f) + printc('-->>>>>>> No output demod file mode',color=bcolors.WARNING) + + #----------------- + # INVERSION OF DATA WITH CMILOS + #----------------- + + if rte == 'RTE' or rte == 'CE' or rte == 'CE+RTE' or rte == 'RTE_seq': + + #check out_dir has "/" character + if out_dir[-1] != "/": + print("Desired Output directory missing / character, will be added") + out_dir = out_dir + "/" + + + if limb is not None: + mask = limb_mask*field_stop[...,np.newaxis] + else: + mask = np.ones((data_size[0],data_size[1],data_shape[-1]))*field_stop[...,np.newaxis] + + if p_milos: + + try: + pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + + except ValueError: + print("Running CMILOS instead!") + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + + else: + if cmilos_fits_opt: + + cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + else: + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + + else: + print(" ") + printc('-->>>>>>> No RTE Inversion mode',color=bcolors.WARNING) + + + #----------------- + # SAVING CONFIG FILE + #----------------- + + if config: + print(" ") + printc('-->>>>>>> Saving copy of input config file ',color=bcolors.OKGREEN) + + dt = datetime.datetime.fromtimestamp(overall_time) + runtime = dt.strftime("%d_%m_%YT%H_%M_%S") + + json.dump(input_dict, open(out_dir + f"config_file_{runtime}.json", "w")) + + print(" ") + printc('--------------------------------------------------------------',color=bcolors.OKGREEN) + printc(f'------------ Reduction Complete: {np.round(time.time() - overall_time,3)} seconds',color=bcolors.OKGREEN) + printc('--------------------------------------------------------------',color=bcolors.OKGREEN) + + + if flat_c: + return data, flat + else: + return data diff --git a/hrt_pipe_sub.py b/hrt_pipe_sub.py new file mode 100644 index 0000000..27aefd1 --- /dev/null +++ b/hrt_pipe_sub.py @@ -0,0 +1,1121 @@ +import numpy as np +from astropy.io import fits +from scipy.ndimage import gaussian_filter +from operator import itemgetter +from utils import * +import os +import time +import subprocess + +def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_exists, imgdirx_flipped, cpos_arr) -> np.ndarray: + """ + load, scale, flip and correct flat + """ + print(" ") + printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) + + start_time = time.time() + + # flat from IP-5 + if '0024151020000' in flat_f or '0024150020000' in flat_f: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=False) + else: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=scale_data) + + if 'IMGDIRX' in header_flat: + header_fltdirx_exists = True + fltdirx_flipped = str(header_flat['IMGDIRX']) + else: + header_fltdirx_exists = False + fltdirx_flipped = 'NO' + + print(f"Flat field shape is {flat.shape}") + # correction based on science data - see if flat and science are both flipped or not + flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) + + flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] + flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states + flat = np.moveaxis(flat, 2,-1) + + print(flat.shape) + + _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position + + print(f"The continuum position of the flat field is at {cpos_f} index position") + + #-------- + # test if the science and flat have continuum at same position + #-------- + + flat = compare_cpos(flat,cpos_f,cpos_arr[0]) + + flat_pmp_temp = str(header_flat['HPMPTSP1']) + + print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") + + #-------- + # correct for missing line in particular flat field + #-------- + + if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + print("This flat has a missing line - filling in with neighbouring pixels") + flat_copy = flat.copy() + flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) + + del flat_copy + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return flat + + +def load_dark(dark_f) -> np.ndarray: + """ + loads dark field from given path + """ + print(" ") + printc('-->>>>>>> Reading Darks',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + dark,_ = get_data(dark_f) + + dark_shape = dark.shape + + if dark_shape != (2048,2048): + + if dark.ndim > 2: + printc("Dark Field Input File has more dimensions than the expected 2048,2048 format: {}",dark_f,color=bcolors.WARNING) + raise ValueError + + printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) + printc("Attempting to correct ",color=bcolors.WARNING) + + + try: + if dark_shape[0] > 2048: + dark = dark[dark_shape[0]-2048:,:] + + except Exception: + printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) + raise ValueError + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return dark + + except Exception: + printc("ERROR, Unable to open and process darks file: {}",dark_f,color=bcolors.FAIL) + + +def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: + """ + subtracts dark field from flat field and science data + """ + print(" ") + print("-->>>>>>> Subtracting dark field") + + start_time = time.time() + + data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] + #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Dark Field correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data, flat + + +def normalise_flat(flat, flat_f, ceny, cenx) -> np.ndarray: + """ + normalise flat fields at each wavelength position to remove the spectral line + """ + print(" ") + printc('-->>>>>>> Normalising Flats',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + norm_fac = np.mean(flat[ceny,cenx, :, :], axis = (0,1))[np.newaxis, np.newaxis, ...] #mean of the central 1k x 1k + flat /= norm_fac + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Normalising flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return flat + + except Exception: + printc("ERROR, Unable to normalise the flat fields: {}",flat_f,color=bcolors.FAIL) + + +def demod_hrt(data,pmp_temp, verbose = True) -> np.ndarray: + ''' + Use constant demodulation matrices to demodulate input data + ''' + if pmp_temp == '50': + demod_data = np.array([[ 0.28037298, 0.18741922, 0.25307596, 0.28119895], + [ 0.40408596, 0.10412157, -0.7225681, 0.20825675], + [-0.19126636, -0.5348939, 0.08181918, 0.64422774], + [-0.56897295, 0.58620095, -0.2579202, 0.2414017 ]]) + + elif pmp_temp == '40': + demod_data = np.array([[ 0.26450154, 0.2839626, 0.12642948, 0.3216773 ], + [ 0.59873885, 0.11278069, -0.74991184, 0.03091451], + [ 0.10833212, -0.5317737, -0.1677862, 0.5923593 ], + [-0.46916953, 0.47738808, -0.43824592, 0.42579797]]) + + else: + printc("Demodulation Matrix for PMP TEMP of {pmp_temp} deg is not available", color = bcolors.FAIL) + if verbose: + printc(f'Using a constant demodulation matrix for a PMP TEMP of {pmp_temp} deg',color = bcolors.OKGREEN) + + demod_data = demod_data.reshape((4,4)) + shape = data.shape + demod = np.tile(demod_data, (shape[0],shape[1],1,1)) + + if data.ndim == 5: + #if data array has more than one scan + data = np.moveaxis(data,-1,0) #moving number of scans to first dimension + + data = np.matmul(demod,data) + data = np.moveaxis(data,0,-1) #move scans back to the end + + elif data.ndim == 4: + #for if data has just one scan + data = np.matmul(demod,data) + + return data, demod + + +def unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode,clean_f,pol_end=4,verbose=True): + """ + unsharp masks the flat fields to blur our polarimetric structures due to solar rotation + clean_f = ['blurring', 'fft'] + """ + flat_demod, demodM = demod_hrt(flat, flat_pmp_temp,verbose) + + norm_factor = np.mean(flat_demod[512:1536,512:1536,0,cpos_arr[0]]) + + flat_demod /= norm_factor + + new_demod_flats = np.copy(flat_demod) + +# b_arr = np.zeros((2048,2048,3,5)) + + if cpos_arr[0] == 0: + wv_range = range(1,6) + + elif cpos_arr[0] == 5: + wv_range = range(5) + + if clean_mode == "QUV": + start_clean_pol = 1 + if verbose: + print("Unsharp Masking Q,U,V") + + elif clean_mode == "UV": + start_clean_pol = 2 + if verbose: + print("Unsharp Masking U,V") + + elif clean_mode == "V": + start_clean_pol = 3 + if verbose: + print("Unsharp Masking V") + + if clean_f == 'blurring': + blur = lambda a: gaussian_filter(a,sigma) + elif clean_f == 'fft': + x = np.fft.fftfreq(2048,1) + fftgaus2d = np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[:,np.newaxis] * np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[np.newaxis] + blur = lambda a : (np.fft.ifftn(fftgaus2d*np.fft.fftn(a.copy()))).real + + for pol in range(start_clean_pol,pol_end): + + for wv in wv_range: #not the continuum + + a = np.copy(np.clip(flat_demod[:,:,pol,wv], -0.02, 0.02)) + b = a - blur(a) +# b_arr[:,:,pol-1,wv-1] = b + c = a - b + + new_demod_flats[:,:,pol,wv] = c + + invM = np.linalg.inv(demodM) + + return np.matmul(invM, new_demod_flats*norm_factor) + + +def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: + """ + correct science data with flat fields + """ + print(" ") + printc('-->>>>>>> Correcting Flatfield',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + if flat_states == 6: + + printc("Dividing by 6 flats, one for each wavelength",color=bcolors.OKGREEN) + + tmp = np.mean(flat,axis=-2) #avg over pol states for the wavelength + + return data / tmp[rows,cols, np.newaxis, :, np.newaxis] + + + elif flat_states == 24: + + printc("Dividing by 24 flats, one for each image",color=bcolors.OKGREEN) + + return data / flat[rows,cols, :, :, np.newaxis] #only one new axis for the scans + + elif flat_states == 4: + + printc("Dividing by 4 flats, one for each pol state",color=bcolors.OKGREEN) + + tmp = np.mean(flat,axis=-1) #avg over wavelength + + return data / tmp[rows,cols, :, np.newaxis, np.newaxis] + else: + print(" ") + printc('-->>>>>>> Unable to apply flat correction. Please insert valid flat_states',color=bcolors.WARNING) + + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data + + except: + printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) + + + +def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): + """ + applies prefilter correction + adapted from SPGPylibs + """ + def _get_v1_index1(x): + index1, v1 = min(enumerate([abs(i) for i in x]), key=itemgetter(1)) + return v1, index1 + + data_shape = data.shape + + for scan in range(data_shape[-1]): + + voltage_list = voltagesData_arr[scan] + + for wv in range(6): + + v = voltage_list[wv] + + vdif = [v - pf for pf in prefilter_voltages] + + v1, index1 = _get_v1_index1(vdif) + + if vdif[index1] >= 0: + v2 = vdif[index1 + 1] + index2 = index1 + 1 + + else: + v2 = vdif[index1-1] + index2 = index1 - 1 + + imprefilter = (prefilter[:,:, index1]*v1 + prefilter[:,:, index2]*v2)/(v1+v2) #interpolation between nearest voltages + + data[:,:,:,wv,scan] /= imprefilter[...,np.newaxis] + + return data + +def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: + """ + apply field stop mask to the science data + """ + print(" ") + printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) + + start_time = time.time() + + field_stop,_ = load_fits('../field_stop/HRT_field_stop.fits') + + field_stop = np.where(field_stop > 0,1,0) + + if header_imgdirx_exists: + if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software + field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction + + data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data, field_stop + +def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): + import random, statistics + from scipy.optimize import curve_fit + def linear(x,a,b): + return a*x + b + my = [] + sy = [] + + x = data_demod[roi>0,0,cpos].flatten() + ids = np.logical_and(x > limit, x < 1.5) + x = x[ids].flatten() + + N = x.size + idx = random.sample(range(N),npoints) + mx = x[idx].mean() + sx = x[idx].std() + xp = np.linspace(x.min(), x.max(), 100) + + A = np.vstack([x, np.ones(len(x))]).T + + # I to Q + yQ = data_demod[roi>0,1,wl].flatten() + yQ = yQ[ids].flatten() + my.append(yQ[idx].mean()) + sy.append(yQ[idx].std()) + cQ = curve_fit(linear,x,yQ,p0=[0,0])[0] + pQ = np.poly1d(cQ) + + # I to U + yU = data_demod[roi>0,2,wl].flatten() + yU = yU[ids].flatten() + my.append(yU[idx].mean()) + sy.append(yU[idx].std()) + cU = curve_fit(linear,x,yU,p0=[0,0])[0] + pU = np.poly1d(cU) + + # I to V + yV = data_demod[roi>0,3,wl].flatten() + yV = yV[ids].flatten() + my.append(yV[idx].mean()) + sy.append(yV[idx].std()) + cV = curve_fit(linear,x,yV,p0=[0,0])[0] + pV = np.poly1d(cV) + + if verbose: + + PLT_RNG = 3 + fig, ax = plt.subplots(figsize=(8, 8)) + ax.scatter(x[idx],yQ[idx],color='red',alpha=0.6,s=10) + ax.plot(xp, pQ(xp), color='red', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yU[idx],color='blue',alpha=0.6,s=10) + ax.plot(xp, pU(xp), color='blue', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yV[idx],color='green',alpha=0.6,s=10) + ax.plot(xp, pV(xp), color='green', linestyle='dashed',linewidth=3.0) + + ax.set_xlim([mx - PLT_RNG * sx,mx + PLT_RNG * sx]) + ax.set_ylim([min(my) - 1.8*PLT_RNG * statistics.mean(sy),max(my) + PLT_RNG * statistics.mean(sy)]) + ax.set_xlabel('Stokes I') + ax.set_ylabel('Stokes Q/U/V') + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.4*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4), style='italic',bbox={'facecolor': 'red', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.55*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4), style='italic',bbox={'facecolor': 'blue', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.7*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4), style='italic',bbox={'facecolor': 'green', 'alpha': 0.1, 'pad': 1}, fontsize=15) +# fig.show() + + print('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4)) + print('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4)) + print('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4)) + +# return cQ,cU,cV, (idx,x,xp,yQ,yU,yV,pQ,pU,pV,mx,sx,my,sy) + else: + ct = np.asarray((cQ,cU,cV)).T + return ct + +def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): + """ + performs cross talk correction for I -> Q,U,V + """ + before_ctalk_data = np.copy(data) + data_shape = data.shape + +# ceny = slice(data_shape[0]//2 - data_shape[0]//4, data_shape[0]//2 + data_shape[0]//4) +# cenx = slice(data_shape[1]//2 - data_shape[1]//4, data_shape[1]//2 + data_shape[1]//4) + + cont_stokes = np.ones(data_shape[-1]) + printc(data_shape[-1],color=bcolors.WARNING) + printc(Ic_mask.shape,color=bcolors.WARNING) + for scan in range(data_shape[-1]): + cont_stokes[scan] = np.mean(data[Ic_mask[...,scan],0,cpos_arr[0],scan]) + print('here1') + for i in range(6): + +# stokes_i_wv_avg = np.mean(data[ceny,cenx,0,i,:], axis = (0,1)) + stokes_i_wv_avg = np.ones(data_shape[-1]) + for scan in range(data_shape[-1]): + stokes_i_wv_avg[scan] = np.mean(data[Ic_mask[...,scan],0,i,scan]) + + print('here2') + if norm_stokes: + #if normed, applies normalised offset to normed stokes + + tmp_param = ctalk_params*np.divide(stokes_i_wv_avg,cont_stokes) + + q_slope = tmp_param[0,0,:] + u_slope = tmp_param[0,1,:] + v_slope = tmp_param[0,2,:] + + q_int = tmp_param[1,0,:] + u_int = tmp_param[1,1,:] + v_int = tmp_param[1,2,:] + + data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int + + data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int + + data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int + print('here3') + + else: + #if not normed, applies raw offset cross talk correction to raw stokes counts + + tmp_param = ctalk_params[0,:,:]*np.divide(stokes_i_wv_avg,cont_stokes) + + q_slope = tmp_param[0,:] + u_slope = tmp_param[1,:] + v_slope = tmp_param[2,:] + + q_int = ctalk_params[1,0,:] + u_int = ctalk_params[1,1,:] + v_int = ctalk_params[1,2,:] + + data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int*stokes_i_wv_avg + + data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int*stokes_i_wv_avg + + data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int*stokes_i_wv_avg + + return data + + +def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): + """ + RTE inversion using CMILOS + """ + print(" ") + printc('-->>>>>>> RUNNING CMILOS ',color=bcolors.OKGREEN) + + try: + CMILOS_LOC = os.path.realpath(__file__) + + CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters + + if os.path.isfile(CMILOS_LOC+'milos'): + printc("Cmilos executable located at:", CMILOS_LOC,color=bcolors.WARNING) + + else: + raise ValueError('Cannot find cmilos:', CMILOS_LOC) + + except ValueError as err: + printc(err.args[0],color=bcolors.FAIL) + printc(err.args[1],color=bcolors.FAIL) + return + + wavelength = 6173.3354 + + for scan in range(int(data_shape[-1])): + + start_time = time.time() + + file_path = data_f[scan] + wave_axis = wve_axis_arr[scan] + hdr = hdr_arr[scan] + + #must invert each scan independently, as cmilos only takes in one dataset at a time + + #get wave_axis from the hdr information of the science scans + if cpos_arr[0] == 0: + shift_w = wave_axis[3] - wavelength + elif cpos_arr[0] == 5: + shift_w = wave_axis[2] - wavelength + # DC TEST + wave_axis = wave_axis - shift_w + + print('It is assumed the wavelength array is given by the hdr') + #print(wave_axis,color = bcolors.WARNING) + print("Wave axis is: ", (wave_axis - wavelength)*1000.) + print('Saving data into dummy_in.txt for RTE input') + + sdata = data[:,:,:,:,scan] + y,x,p,l = sdata.shape + #print(y,x,p,l) + + filename = 'dummy_in.txt' + with open(filename,"w") as f: + for i in range(x): + for j in range(y): + for k in range(l): + f.write('%e %e %e %e %e \n' % (wave_axis[k],sdata[j,i,0,k],sdata[j,i,1,k],sdata[j,i,2,k],sdata[j,i,3,k])) #wv, I, Q, U, V + del sdata + + printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) + + cmd = CMILOS_LOC+"./milos" + cmd = fix_path(cmd) + + if rte == 'RTE': + rte_on = subprocess.call(cmd+" 6 15 0 0 dummy_in.txt > dummy_out.txt",shell=True) + if rte == 'CE': + rte_on = subprocess.call(cmd+" 6 15 2 0 dummy_in.txt > dummy_out.txt",shell=True) + if rte == 'CE+RTE': + rte_on = subprocess.call(cmd+" 6 15 1 0 dummy_in.txt > dummy_out.txt",shell=True) + + #print(rte_on) + + printc(' ---- >>>>> Reading results.... ',color=bcolors.OKGREEN) + del_dummy = subprocess.call("rm dummy_in.txt",shell=True) + #print(del_dummy) + + res = np.loadtxt('dummy_out.txt') + npixels = res.shape[0]/12. + #print(npixels) + #print(npixels/x) + result = np.zeros((12,y*x)).astype(float) + rte_invs = np.zeros((12,y,x)).astype(float) + for i in range(y*x): + result[:,i] = res[i*12:(i+1)*12] + result = result.reshape(12,y,x) + result = np.einsum('ijk->ikj', result) + rte_invs = result + del result + rte_invs_noth = np.copy(rte_invs) + + """ + From 0 to 11 + Counter (PX Id) + Iterations + Strength + Inclination + Azimuth + Eta0 parameter + Doppler width + Damping + Los velocity + Constant source function + Slope source function + Minimum chisqr value + """ + + noise_in_V = np.mean(data[:,:,3,cpos_arr[0],:]) + low_values_flags = np.max(np.abs(data[:,:,3,:,scan]),axis=-1) < noise_in_V # Where values are low + + rte_invs[2,low_values_flags] = 0 + rte_invs[3,low_values_flags] = 0 + rte_invs[4,low_values_flags] = 0 + + #np.savez_compressed(out_dir+'_RTE', rte_invs=rte_invs, rte_invs_noth=rte_invs_noth) + + del_dummy = subprocess.call("rm dummy_out.txt",shell=True) + #print(del_dummy) + + """ + #vlos S/C vorrection + v_x, v_y, v_z = hdr['HCIX_VOB']/1000, hdr['HCIY_VOB']/1000, hdr['HCIZ_VOB']/1000 + + #need line of sight velocity, should be total HCI velocity in km/s, with sun at origin. + #need to take care for velocities moving towards the sun, (ie negative) #could use continuum position as if towards or away + + if cpos_arr[scan] == 5: #moving away, redshifted + dir_factor = 1 + + elif cpos_arr[scan] == 0: #moving towards, blueshifted + dir_factor == -1 + + v_tot = dir_factor*math.sqrt(v_x**2 + v_y**2+v_z**2) #in km/s + + rte_invs_noth[8,:,:] = rte_invs_noth[8,:,:] - v_tot + """ + + rte_data_products = np.zeros((6,rte_invs_noth.shape[1],rte_invs_noth.shape[2])) + + rte_data_products[0,:,:] = rte_invs_noth[9,:,:] + rte_invs_noth[10,:,:] #continuum + rte_data_products[1,:,:] = rte_invs_noth[2,:,:] #b mag strength + rte_data_products[2,:,:] = rte_invs_noth[3,:,:] #inclination + rte_data_products[3,:,:] = rte_invs_noth[4,:,:] #azimuth + rte_data_products[4,:,:] = rte_invs_noth[8,:,:] #vlos + rte_data_products[5,:,:] = rte_invs_noth[2,:,:]*np.cos(rte_invs_noth[3,:,:]*np.pi/180.) #blos + + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + + if out_rte_filename is None: + filename_root = str(file_path.split('.fits')[0][-10:]) + else: + if isinstance(out_rte_filename, list): + filename_root = out_rte_filename[scan] + + elif isinstance(out_rte_filename, str): + filename_root = out_rte_filename + + else: + filename_root = str(file_path.split('.fits')[0][-10:]) + print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products + hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].hdrheader= hdr + hdu_list[0].data = rte_data_products[5,:,:] + hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) + # DC change 20211101 Gherdardo needs separate fits files from inversion + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[3,:,:] + hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[2,:,:] + hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[1,:,:] + hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[4,:,:] + hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[0,:,:] + hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- CMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + +def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): + """ + RTE inversion using CMILOS + """ + print(" ") + printc('-->>>>>>> RUNNING CMILOS ',color=bcolors.OKGREEN) + + try: + CMILOS_LOC = os.path.realpath(__file__) + + CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters + + if os.path.isfile(CMILOS_LOC+'milos'): + printc("Cmilos-fits executable located at:", CMILOS_LOC,color=bcolors.WARNING) + + else: + raise ValueError('Cannot find cmilos-fits:', CMILOS_LOC) + + except ValueError as err: + printc(err.args[0],color=bcolors.FAIL) + printc(err.args[1],color=bcolors.FAIL) + return + + wavelength = 6173.3354 + + for scan in range(int(data_shape[-1])): + + start_time = time.time() + + file_path = data_f[scan] + wave_axis = wve_axis_arr[scan] + hdr = hdr_arr[scan] + + #must invert each scan independently, as cmilos only takes in one dataset at a time + + #get wave_axis from the hdr information of the science scans + if cpos_arr[0] == 0: + shift_w = wave_axis[3] - wavelength + elif cpos_arr[0] == 5: + shift_w = wave_axis[2] - wavelength + + wave_axis = wave_axis - shift_w + + print('It is assumed the wavelength array is given by the hdr') + #print(wave_axis,color = bcolors.WARNING) + print("Wave axis is: ", (wave_axis - wavelength)*1000.) + print('Saving data into dummy_in.txt for RTE input') + + sdata = data[:,:,:,:,scan] + y,x,p,l = sdata.shape + + #create hdr with wavelength positions + hdr = fits.Header() + print(wave_axis[0]) + hdr['LAMBDA0'] = wave_axis[0]#needs it in Angstrom 6173.1 etc + hdr['LAMBDA1'] = wave_axis[1] + hdr['LAMBDA2'] = wave_axis[2] + hdr['LAMBDA3'] = wave_axis[3] + hdr['LAMBDA4'] = wave_axis[4] + hdr['LAMBDA5'] = wave_axis[5] + + + #write out data to temp fits for cmilos-fits input + input_arr = np.transpose(sdata, axes = (3,2,0,1)) #must transpose due to cfitsio (wl,pol,y,x) #3201 originally + + # DC CHANGE (same number of digits of cmilos) +# hdr['LAMBDA0'] = float('%e' % wave_axis[0])#needs it in Angstrom 6173.1 etc +# hdr['LAMBDA1'] = float('%e' % wave_axis[1]) +# hdr['LAMBDA2'] = float('%e' % wave_axis[2]) +# hdr['LAMBDA3'] = float('%e' % wave_axis[3]) +# hdr['LAMBDA4'] = float('%e' % wave_axis[4]) +# hdr['LAMBDA5'] = float('%e' % wave_axis[5]) +# printc('-->>>>>>> CHANGING DATA PRECISION ',color=bcolors.OKGREEN) +# for w in range(l): +# for s in range(p): +# for i in range(y): +# for j in range(x): +# input_arr[w,s,i,j] = float('%e' % input_arr[w,s,i,j]) + # DC CHANGE END + + hdu1 = fits.PrimaryHDU(data=input_arr, header = hdr) + + #mask + mask = np.ones((sdata.shape[0],sdata.shape[1])) #change this for fdt + hdu2 = fits.ImageHDU(data=mask) + + #write out to temp fits + hdul_tmp = fits.HDUList([hdu1, hdu2]) + hdul_tmp.writeto(out_dir+'temp_cmilos_io.fits', overwrite=True) + + del sdata + + printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) + + cmd = CMILOS_LOC+"milos" + #cmd = fix + #fix_path(cmd) + print(cmd) + + if rte == 'RTE': + rte_on = subprocess.call(cmd+f" 6 15 0 {out_dir+'temp_cmilos_io.fits'}",shell=True) + if rte == 'CE': + rte_on = subprocess.call(cmd+f" 6 15 2 {out_dir+'temp_cmilos_io.fits'}",shell=True) + if rte == 'CE+RTE': + rte_on = subprocess.call(cmd+f" 6 15 1 {out_dir+'temp_cmilos_io.fits'}",shell=True) + + print(rte_on) + + printc(' ---- >>>>> Reading results.... ',color=bcolors.OKGREEN) + #print(del_dummy) + + with fits.open(out_dir+'temp_cmilos_io.fits') as hdu_list: + rte_out = hdu_list[0].data + #hdu_list.writeto(out_dir+'rte_out.fits', overwrite=True) + + del input_arr + + """ + From 0 to 11 + Iterations + Strength + Inclination + Azimuth + Eta0 parameter + Doppler width + Damping/aa + Los velocity + alfa? Counter PID? + Constant source function + Slope source function + Minimum chisqr value + """ + + """ + Direct from cmilos-fits/milos.c + inv->iter = malloc(npix*sizeof(int)); + inv->B = malloc(npix*sizeof(double)); + inv->gm = malloc(npix*sizeof(double)); + inv->az = malloc(npix*sizeof(double)); + inv->eta0 = malloc(npix*sizeof(double)); + inv->dopp = malloc(npix*sizeof(double)); + inv->aa = malloc(npix*sizeof(double)); + inv->vlos = malloc(npix*sizeof(double)); //km/s + inv->alfa = malloc(npix*sizeof(double)); //stay light factor + inv->S0 = malloc(npix*sizeof(double)); + inv->S1 = malloc(npix*sizeof(double)); + inv->nchisqrf = malloc(npix*sizeof(double)); + + """ + + """ + noise_in_V = np.mean(data[:,:,3,cpos_arr[0],:]) + low_values_flags = np.max(np.abs(data[:,:,3,:,scan]),axis=-1) < noise_in_V # Where values are low + + rte_out[2,low_values_flags] = 0 #not sure about 2,3,4 indexing here + rte_out[3,low_values_flags] = 0 + rte_out[4,low_values_flags] = 0 + """ + + rte_data_products = np.zeros((6,rte_out.shape[1],rte_out.shape[2])) + + rte_data_products[0,:,:] = rte_out[9,:,:] + rte_out[10,:,:] #continuum + rte_data_products[1,:,:] = rte_out[1,:,:] #b mag strength + rte_data_products[2,:,:] = rte_out[2,:,:] #inclination + rte_data_products[3,:,:] = rte_out[3,:,:] #azimuth + rte_data_products[4,:,:] = rte_out[7,:,:] #vlos + rte_data_products[5,:,:] = rte_out[1,:,:]*np.cos(rte_out[2,:,:]*np.pi/180.) #blos + + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + + if out_rte_filename is None: + filename_root = str(file_path.split('.fits')[0][-10:]) + else: + if isinstance(out_rte_filename, list): + filename_root = out_rte_filename[scan] + + elif isinstance(out_rte_filename, str): + filename_root = out_rte_filename + + else: + filename_root = str(file_path.split('.fits')[0][-10:]) + print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products + hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[5,:,:] + hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) + # DC change 20211101 Gherdardo needs separate fits files from inversion + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[3,:,:] + hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[2,:,:] + hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[1,:,:] + hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[4,:,:] + hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[0,:,:] + hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + + +def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): + """ + RTE inversion using PMILOS + """ + print(" ") + printc('-->>>>>>> RUNNING PMILOS ',color=bcolors.OKGREEN) + + try: + PMILOS_LOC = os.path.realpath(__file__) + + PMILOS_LOC = PMILOS_LOC[:-15] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py + + if os.path.isfile(PMILOS_LOC+'pmilos.x'): + printc("Pmilos executable located at:", PMILOS_LOC,color=bcolors.WARNING) + + else: + raise ValueError('Cannot find pmilos:', PMILOS_LOC) + + except ValueError as err: + printc(err.args[0],color=bcolors.FAIL) + printc(err.args[1],color=bcolors.FAIL) + return + + wavelength = 6173.3354 + + for scan in range(int(data_shape[-1])): + + start_time = time.time() + + file_path = data_f[scan] + wave_axis = wve_axis_arr[scan] + + #must invert each scan independently, as cmilos only takes in one dataset at a time + + #get wave_axis from the hdr information of the science scans + if cpos_arr[0] == 0: + shift_w = wave_axis[3] - wavelength + elif cpos_arr[0] == 5: + shift_w = wave_axis[2] - wavelength + + wave_axis = wave_axis - shift_w + + print('It is assumed the wavelength array is given by the hdr') + #print(wave_axis,color = bcolors.WARNING) + print("Wave axis is: ", (wave_axis - wavelength)*1000.) + print('Saving data into ./p-milos/run/data/input_tmp.fits for pmilos RTE input') + + #write wavelengths to wavelength.fits file for the settings + + wave_input = np.zeros((2,6)) #cfitsio reads dimensions in opposite order + wave_input[0,:] = 1 + wave_input[1,:] = wave_axis + + print(wave_axis) + + hdr = fits.Header() + + primary_hdu = fits.PrimaryHDU(wave_input, header = hdr) + hdul = fits.HDUList([primary_hdu]) + hdul.writeto(f'./p-milos/run/wavelength_tmp.fits', overwrite=True) + + sdata = data[:,:,:,:,scan].T + sdata = sdata.astype(np.float32) + #create input fits file for pmilos + hdr = fits.Header() + + hdr['CTYPE1'] = 'HPLT-TAN' + hdr['CTYPE2'] = 'HPLN-TAN' + hdr['CTYPE3'] = 'STOKES' #check order of stokes + hdr['CTYPE4'] = 'WAVE-GRI' + + primary_hdu = fits.PrimaryHDU(sdata, header = hdr) + hdul = fits.HDUList([primary_hdu]) + hdul.writeto(f'./p-milos/run/data/input_tmp.fits', overwrite=True) + + if rte == 'RTE': + cmd = "mpiexec -n 64 ../pmilos.x pmilos.minit" #../milos.x pmilos.mtrol" ## + + if rte == 'CE': + cmd = "mpiexec -np 16 ../pmilos.x pmilos_ce.minit" + + if rte == 'CE+RTE': + print("CE+RTE not possible on PMILOS, performing RTE instead") + cmd = "mpiexec -np 16 ../pmilos.x pmilos.minit" + + if rte == 'RTE_seq': + cmd = '../milos.x pmilos.mtrol' + + del sdata + #need to change settings for CE or CE+RTE in the pmilos.minit file here + + printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) + + cwd = os.getcwd() + os.chdir("./p-milos/run/") + rte_on = subprocess.call(cmd,shell=True) + os.chdir(cwd) + + if rte == 'CE': + out_file = 'inv__mod_ce.fits' # not sure about this one + + else: + out_file = 'inv__mod.fits' #only when one datacube and 16 processors + + with fits.open(f'./p-milos/run/results/{out_file}') as hdu_list: + result = hdu_list[0].data + + #del_dummy = subprocess.call(f"rm ./p-milos/run/results/{out_file}.fits",shell=True) + del_dummy = subprocess.call(f"rm ./p-milos/run/results/{out_file}",shell=True) #must delete the output file + + #result has dimensions [rows,cols,13] + result = np.moveaxis(result,0,2) + print(result.shape) + #printc(f' ---- >>>>> You are HERE .... ',color=bcolors.WARNING) + """ + PMILOS Output 13 columns + 0. eta0 = line-to-continuum absorption coefficient ratio + 1. B = magnetic field strength [Gauss] + 2. vlos = line-of-sight velocity [km/s] + 3. dopp = Doppler width [Angstroms] + 4. aa = damping parameter + 5. gm = magnetic field inclination [deg] + 6. az = magnetic field azimuth [deg] + 7. S0 = source function constant + 8. S1 = source function gradient + 9. mac = macroturbulent velocity [km/s] + 10. filling factor of the magnetic component [0-1] + 11. Number of iterations performed + 12. Chisqr value + """ + + rte_data_products = np.zeros((6,result.shape[0],result.shape[1])) + + rte_data_products[0,:,:] = result[:,:,7] + result[:,:,8] #continuum + rte_data_products[2,:,:] = result[:,:,5] #inclination + rte_data_products[3,:,:] = result[:,:,6] #azimuth + rte_data_products[4,:,:] = result[:,:,2] #vlos + rte_data_products[5,:,:] = result[:,:,1]*np.cos(result[:,:,5]*np.pi/180.) #blos + + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + + #flipping taken care of for the field stop in the hrt_pipe + #printc(f' ---- >>>>> and HERE now .... ',color=bcolors.WARNING) + if out_rte_filename is None: + filename_root = str(file_path.split('.fits')[0][-10:]) + else: + filename_root = out_rte_filename + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products + hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[5,:,:] + hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) + # DC change 20211101 Gherdardo needs separate fits files from inversion + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[3,:,:] + hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[2,:,:] + hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[1,:,:] + hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[4,:,:] + hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr + hdu_list[0].data = rte_data_products[0,:,:] + hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- PMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) -- GitLab From 46c06ab4598465bb0530f709e4e10300df52f904 Mon Sep 17 00:00:00 2001 From: jonas Date: Mon, 15 Nov 2021 12:22:56 +0100 Subject: [PATCH 09/34] readme update + setup.sh --- README.md | 121 ++++++++++++++++++++++++++++-------------------------- setup.sh | 35 ++++++++++++++++ 2 files changed, 98 insertions(+), 58 deletions(-) create mode 100644 setup.sh diff --git a/README.md b/README.md index 032cac5..4184c30 100755 --- a/README.md +++ b/README.md @@ -3,93 +3,58 @@ Reduction software for SO/PHI-HRT instrument on the ESA Solar Orbiter ## **PHI-HRT data reduction** 1. read in science data (+scaling) open path option + open for several scans at once -2. read in flat field (+scaling)- just accepts one flat field fits file +2. read in flat field (+scaling)- accepts only one flat field fits file 3. read in dark field (+scaling) -4. apply dark field -5. option to clean flat field with unsharp masking (Stokes V only) +4. apply dark field (to only science - assumes flat is dark fielded) +5. option to clean flat field with unsharp masking (Stokes QUV, UV or V) 6. normalise flat field 7. apply flat field 8. prefilter correction -9. read in field stop -10. apply field stop -11. demodulate with const demod matrix
+9. apply field stop +10. demodulate with const demod matrix
a) option to output demod to fits file
-12. normalise to quiet sun -13. calibration
+11. normalise to quiet sun +12. calibration
a) cross talk correction
- (if required) b) ghost correction - **not implemented yet**
-14. rte inversion with cmilos
- a) output rte data products to fits file
+13. rte inversion with cmilos
+ a) output rte data products to fits files
-#### **CONFIGURATION** -Any and all steps can be turned on or off as you wish using the keywords in the input json file passed to the `phihrt_pipe` function - -See `/input_jsons/create_input_json.py` for example to create json file - -## **DOWNLOAD INPUT FILES** - -This needs the 'dataproc' environment - see **SETUP** - -EITHER: download from the PHI Image Database (recommended): https://www2.mps.mpg.de/services/proton/phi/imgdb/ - -Suggested filters for HRT science data: -- **KEYWORD DETECTOR = 'HRT'**
-- **Filename\* like \*L1_phi-hrt-ilam_date\*** - -To download via the command line (eg: if you want to save the files on a server and not locally) -``` -wget --user yourusername --password yourpassword file_web_address -gunzip file.gz -``` -Gunzip used to unpack the .gz to the file you want
-Can also use `/download/download_from_db.py` to perform multi download from database +## **SETUP** -Instructions: - 1. From the database find the files you wish to download - 2. Copy the 'Download File List' that the database will generate - 3. Paste into the `file_names.txt` file - 4. Create a `.env` file with your MPS windows login:
- ```text= - USER_NAME = - PHIDATAPASSWORD = - ``` - 5. Set the target download folder in the `download_from_db.py` file - 6. Run the file (will require dotenv python module to be installed) +Operating System Required: Linux -OR : use `download_files.py` to download images from the attic repository: https://www2.mps.mpg.de/services/proton/phi/fm/attic/ +If running on bob MPS server and you have access -## **SETUP** +Run bash script - setup.sh - to skip the first four steps -IMPORTANT -Operating System: Linux +OTHERWISE: -1. Compile milos in both cmilos-fits folder and cmilos folder (cmilos-fits faster): +1. Compile milos in both cmilos-fits folder and cmilos folder (cmilos-fits): ```bash make clear make ``` -2. FOR P-MILOS - multiple steps required - ASSUMING RUNNING ON **BOB** SERVER -- load openmpi_gcc -- load fftw +2. P-MILOS - multiple steps required - ASSUMING RUNNING ON **BOB** SERVER +- module load openmpi_gcc +- module load fftw - load cfitsio (or export through .bashrc) -COMPILE ```bash make clean make ``` -3. Setup virtual environment from requirements.txt +3. Setup virtual environment from requirements.txt with PIP or CONDA using pip - REQUIRES PYTHON >= 3.6 ```bash pip install -r requirements.txt ``` -using conda (Anaconda3) - creates virtual environment called 'dataproc' +OR using conda (Anaconda3) - creates virtual environment called 'dataproc' ```bash conda env create -f environment.yml ``` @@ -101,15 +66,54 @@ source activate dataproc 5. Download files - see **DOWNLOAD INPUT FILES** Section -5. Generate json files with the science, dark and flat you desire to reduce +5. Generate json files with the science, dark and flat you desire to reduce, ensure that all keywords from in the example are used (for limb images you must know the limb in the FOV - can only reduce multiple limb files at the same runtime if all the same limb in FOV) -6. Make sure the correct input.json file is being given to `hrt_pipe` in ```run.py``` +6. Make sure the correct input.json file is given to `hrt_pipe` in ```run.py``` 7. Execute ```run.py``` ```bash python run.py ``` + +## **CONFIGURATION** + +Any and all steps can be turned on or off as you wish using the keywords in the input json file passed to the `phihrt_pipe` function + +See `/input_jsons/create_input_json.py` for example to create json file + +## **DOWNLOAD INPUT FILES** + +This needs the 'dataproc' environment - see **SETUP** + +EITHER: download from the PHI Image Database (recommended): https://www2.mps.mpg.de/services/proton/phi/imgdb/ + +Suggested filters for HRT science data: +- **KEYWORD DETECTOR = 'HRT'**
+- **Filename\* like \*L1_phi-hrt-ilam_date\*** + +To download via the command line (eg: if you want to save the files on a server and not locally) +``` +wget --user yourusername --password yourpassword file_web_address +gunzip file.gz +``` +Gunzip used to unpack the .gz to the file you want
+ +Can also use `/download/download_from_db.py` to perform multi download from database: + +Instructions: + 1. From the database find the files you wish to download + 2. Copy the 'Download File List' that the database will generate + 3. Paste into the `file_names.txt` file + 4. Create a `.env` file with your MPS Windows login:
+ ```text= + USER_NAME = + PHIDATAPASSWORD = + ``` + 5. Set the target download folder in the `download_from_db.py` file + 6. Run the file (will require dotenv python module to be installed - included in `dataproc`) + +OR : use `download_files.py` to download images from the attic repository: https://www2.mps.mpg.de/services/proton/phi/fm/attic/ ## **OUTPUT** #### **Stokes File** @@ -181,4 +185,5 @@ Daniele Calchetti - Max Planck Institute for Solar System Research, Goettingen, - SPGPylibs for the foundation, from which it was expanded upon - CMILOS: RTE INVERSION C code for SO-PHI (based on the IDL code MILOS by D. Orozco) Author: juanp (IAA-CSIC) -- CMILOS-FITS: RTE INVERSION C code with fits interace, fits interfacing developed by Philipp Loeschl (MPS) \ No newline at end of file +- CMILOS-FITS: CMILOS with fits interace, fits interfacing developed by Philipp Loeschl (MPS) +- P-MILOS: Parallellised RTE INVERSION C code Authors: Manuel Cabrera, Juan P. Cobos, Luis Bellot Rubio (IAA-CSIC) \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100644 index 0000000..c686870 --- /dev/null +++ b/setup.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +module load openmpi_gcc +module load anaconda/3-5.0.1 +modlue load fftw/3.3.5 + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/local/cfitsio/cfitsio-3.350/lib + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/local/cfitsio/cfitsio-3.350/include + +#compile the rte codes + +cd ./cmilos +make clear +make + +cd .. + +cd ./cmilos-fits +make clear +make + +cd .. + +cd p-milos +make clean +make + +cd .. + +conda env create -f environment.yml +#pip install -r requrements.txt + +source activate dataproc + -- GitLab From 44df7e0c2dc86daca80f7c76f00ed61fb635689d Mon Sep 17 00:00:00 2001 From: jonas Date: Mon, 15 Nov 2021 12:33:13 +0100 Subject: [PATCH 10/34] ignore executables --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b51dfd6..9090e3b 100755 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ dummy*.txt # cmilos/* cmilos-fits/milos cmilos-fits/*.o +cmilos/milos +cmilos/*.o _RTE.npz *.npz .env -- GitLab From bc0948ebfe4d04c83e449022c1a96e7417c87fcf Mon Sep 17 00:00:00 2001 From: dcalc <35452781+dcalc@users.noreply.github.com> Date: Thu, 18 Nov 2021 14:44:49 +0100 Subject: [PATCH 11/34] dc update ct improvements ghost out of ct computation intermediate result cmilos parameters fixed --- cmilos-fits/calculosCompartidos.o | Bin 0 -> 14648 bytes cmilos-fits/create_cuantic.o | Bin 0 -> 6016 bytes cmilos-fits/defines.h | 45 +- cmilos-fits/fgauss.o | Bin 0 -> 3824 bytes cmilos-fits/fits.o | Bin 0 -> 10944 bytes cmilos-fits/fvoigt.o | Bin 0 -> 4144 bytes cmilos-fits/lib.c | 4 +- cmilos-fits/lib.o | Bin 0 -> 13464 bytes cmilos-fits/me_der.o | Bin 0 -> 40480 bytes cmilos-fits/mil_sinrf.o | Bin 0 -> 15984 bytes cmilos-fits/milos | Bin 0 -> 134520 bytes cmilos-fits/milos.c | 745 +++++--- cmilos-fits/milos.o | Bin 0 -> 66864 bytes cmilos-fits/milos_David.c | 1206 +++++++++++++ .../milos_bk_antes_cambios_estimaciones.c | 1501 +++++++++++++++++ cmilos-fits/test_time.c | 14 + cmilos/defines.h | 16 +- cmilos/milos | Bin 125480 -> 125480 bytes cmilos/milos.o | Bin 61784 -> 61744 bytes src/__pycache__/hrt_pipe.cpython-38.pyc | Bin 0 -> 17938 bytes src/__pycache__/hrt_pipe_sub.cpython-38.pyc | Bin 0 -> 24401 bytes src/__pycache__/utils.cpython-38.pyc | Bin 0 -> 12666 bytes src/hrt_pipe.py | 169 +- src/hrt_pipe_sub.py | 153 +- 24 files changed, 3519 insertions(+), 334 deletions(-) create mode 100644 cmilos-fits/calculosCompartidos.o create mode 100644 cmilos-fits/create_cuantic.o create mode 100644 cmilos-fits/fgauss.o create mode 100644 cmilos-fits/fits.o create mode 100644 cmilos-fits/fvoigt.o create mode 100644 cmilos-fits/lib.o create mode 100644 cmilos-fits/me_der.o create mode 100644 cmilos-fits/mil_sinrf.o create mode 100644 cmilos-fits/milos create mode 100644 cmilos-fits/milos.o create mode 100644 cmilos-fits/milos_David.c create mode 100644 cmilos-fits/milos_bk_antes_cambios_estimaciones.c create mode 100644 cmilos-fits/test_time.c create mode 100644 src/__pycache__/hrt_pipe.cpython-38.pyc create mode 100644 src/__pycache__/hrt_pipe_sub.cpython-38.pyc create mode 100644 src/__pycache__/utils.cpython-38.pyc diff --git a/cmilos-fits/calculosCompartidos.o b/cmilos-fits/calculosCompartidos.o new file mode 100644 index 0000000000000000000000000000000000000000..7a2c59611575655749f93e96db2437d6898e3ef3 GIT binary patch literal 14648 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 TPidA-f5h}ZmeDi@cK!bV(4cNH literal 0 HcmV?d00001 diff --git a/cmilos-fits/defines.h b/cmilos-fits/defines.h index 19a2626..9d74070 100755 --- a/cmilos-fits/defines.h +++ b/cmilos-fits/defines.h @@ -17,7 +17,7 @@ //--------------------------------------------------------- // USER CONFIGURATION -#define CENTRAL_WL 6173.34 +#define CENTRAL_WL 6173.335400 //############################################## @@ -33,15 +33,40 @@ #define LIMITE_INFERIOR_PRECISION_SINCOS pow(2.0,-39) //############################################# -//INITIAL MODEL -#define INITIAL_MODEL_B 1200 -#define INITIAL_MODEL_GM 170 -#define INITIAL_MODEL_AZI 20 -#define INITIAL_MODEL_ETHA0 8 -#define INITIAL_MODEL_LAMBDADOPP 0.04 //en A -#define INITIAL_MODEL_AA 0.18 -#define INITIAL_MODEL_VLOS 0.05 // Km/s -#define INITIAL_MODEL_S0 0.35 +//INITIAL MODEL +// #define INITIAL_MODEL_B 1200 +// #define INITIAL_MODEL_GM 170 +// #define INITIAL_MODEL_AZI 20 +// #define INITIAL_MODEL_ETHA0 8 +// #define INITIAL_MODEL_LAMBDADOPP 0.04 //en A +// #define INITIAL_MODEL_AA 0.18 +// #define INITIAL_MODEL_VLOS 0.05 // Km/s +// #define INITIAL_MODEL_S0 0.35 +// #define INITIAL_MODEL_S1 0.85 + +// RTE init model config ONBOARD +// Inv Iterations = 15 +// Initial Model Continuum Absoprtion = 12.0000 // INITIAL_MODEL_ETHA0 +// Initial Model Vector Magnetic Field Strength = 1200.00000 // INITIAL_MODEL_B +// Initial Model Line-Of-Sight Velocity = 0.05000 // INITIAL_MODEL_VLOS +// Initial Model Doppler Width Of Line = 0.05000 // INITIAL_MODEL_LAMBDADOPP +// Initial Model Damping Parameter = 0.05000 // INITIAL_MODEL_AA +// Initial Model Vector Magnetic Field Inclination = 170.00000 // INITIAL_MODEL_GM +// Initial Model Vector Magnetic Field Azimuth = 25.00000 // INITIAL_MODEL_AZI +// Initial Model Source Function Ordinate At Origin = 0.30000 // INITIAL_MODEL_S0 +// Initial Model Source Function Slope = 0.80000 // INITIAL_MODEL_S1 +// Wavelength Setting Initial Sampling Wavelength = 6173.20117 +// Wavelength Setting Spectral Line Step = 0.07000 +// Wavelength Setting Wavelength Of Line Continuum = 6173.04117 (blue) 6173.64117 (red) + +#define INITIAL_MODEL_B 400 +#define INITIAL_MODEL_GM 30 +#define INITIAL_MODEL_AZI 120 +#define INITIAL_MODEL_ETHA0 3 +#define INITIAL_MODEL_LAMBDADOPP 0.025 //en A +#define INITIAL_MODEL_AA 1.0 +#define INITIAL_MODEL_VLOS 0.01 // Km/s +#define INITIAL_MODEL_S0 0.15 #define INITIAL_MODEL_S1 0.85 diff --git a/cmilos-fits/fgauss.o b/cmilos-fits/fgauss.o new file mode 100644 index 0000000000000000000000000000000000000000..a468fbe1dbae07db2291b511df58c05bd78d91d7 GIT binary patch literal 3824 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 literal 0 HcmV?d00001 diff --git a/cmilos-fits/lib.c b/cmilos-fits/lib.c index 8450760..47615dd 100755 --- a/cmilos-fits/lib.c +++ b/cmilos-fits/lib.c @@ -81,8 +81,8 @@ double fchisqr(PRECISION * spectra,int nspectro,PRECISION *spectro,PRECISION *w, dif=spectra[i+nspectro*j]-spectro[i+nspectro*j]; opa+= (dif*dif); } - // TOT+=((w[j]*opa)/(sig[j]*sig[j])); - TOT+= opa;///(sig[j]*sig[j]); + TOT+=((w[j]*opa)/(sig[j]*sig[j])); + //TOT+= opa;///(sig[j]*sig[j]); } //return TOT/15; diff --git a/cmilos-fits/lib.o b/cmilos-fits/lib.o new file mode 100644 index 0000000000000000000000000000000000000000..734d22241eeea6f356e24c58ca6ab86442bf967b GIT binary patch literal 13464 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 OsJcF>ezM>FumAt30R@Nv literal 0 HcmV?d00001 diff --git a/cmilos-fits/mil_sinrf.o b/cmilos-fits/mil_sinrf.o new file mode 100644 index 0000000000000000000000000000000000000000..28697c53615b100ffad0d437cf9082b4df917cd6 GIT binary patch literal 15984 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 GZT~-o%$Lgm literal 0 HcmV?d00001 diff --git a/cmilos-fits/milos b/cmilos-fits/milos new file mode 100644 index 0000000000000000000000000000000000000000..5c2ff54a991c7742470af8d8af89dd43fef2fb76 GIT binary patch literal 134520 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 literal 0 HcmV?d00001 diff --git a/cmilos-fits/milos.c b/cmilos-fits/milos.c index a089d77..b4ebb58 100644 --- a/cmilos-fits/milos.c +++ b/cmilos-fits/milos.c @@ -138,7 +138,7 @@ int main(int argc,char **argv){ double slight; double toplim; int miter; - PRECISION weight[4]={1.,1.,1.,1.}; + PRECISION weight[4]={1.,10.,10.,4.}; //{1.,1.,1.,1.}; int nweight; // CONFIGURACION DE PARAMETROS A INVERTIR @@ -688,12 +688,12 @@ int main_sequential(int argc,char **argv){ * spectra : IQUV por filas, longitud ny=nlambda */ -int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlambda,PRECISION *spectro,int nspectro, +int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlambda,PRECISION *spectro,int nspectro, Init_Model *initModel, PRECISION *spectra,int err,double *chisqrf, int *iterOut, - double slight, double toplim, int miter, PRECISION * weight,int nweight, int * fix, + double slight, double toplim, int miter, PRECISION * weight,int nweight, int * fix, PRECISION *sigma, double filter, double ilambda, double noise, double *pol, double getshi,int triplete) -{ +{ int * diag; int iter; @@ -706,7 +706,7 @@ int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlam double chisqr,ochisqr; int nspectra,nd_spectra,clanda,ind; Init_Model model; - + //Genera aleatoriamente los componentes del vector tiempo(semi); //semilla para generar los valores de la lista de forma aleatoria con srand srand((char)semi); @@ -718,19 +718,19 @@ int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlam nfree=CalculaNfree(spectro,nspectro); //printf("\n nfree! %d:\n",nfree); //exit(-1); - - + + if(nfree==0){ return -1; //'NOT ENOUGH POINTS' } - + flambda=ilambda; - + if(fix==NULL){ fixed=calloc(NTERMS,sizeof(double)); for(i=0;iB); + printf("%f\n",initModel->gm); + printf("%f\n",initModel->az); + printf("%f \n",initModel->eta0); + printf("%f\n",initModel->dopp); + printf("%f\n",initModel->aa); + printf("%f\n",initModel->vlos); //km/s + //printf("alfa \t:%f\n",initModel.alfa); //stay light factor + printf("%f\n",initModel->S0); + printf("%f\n",initModel->S1); + printf("%.10e\n",ochisqr); +*/ }while(iter<=miter); // && !clanda); @@ -848,37 +884,39 @@ int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlam *chisqrf=ochisqr; - + //For debugging -> flambda en lugar de AA + //initModel->aa = flambda; + if(fix==NULL) free(fixed); return 1; -} +} int CalculaNfree(PRECISION *spectro,int nspectro){ int nfree,i,j; nfree=0; - - /* - for(j=0;j<4*nspectro;j++){ - if(spectro[j]!=0.0){ - nfree++; - } - } - nfree=nfree-NTERMS;//NTERMS; - */ - + + + // for(j=0;j<4*nspectro;j++){ + // if(spectro[j]!=0.0){ + // nfree++; + // } + // } + // nfree=nfree-NTERMS;//NTERMS; + + nfree = (nspectro*NPARMS) - NTERMS; - + return nfree; } /* -* +* * * Cálculo de las estimaciones clásicas. * @@ -891,7 +929,7 @@ int CalculaNfree(PRECISION *spectro,int nspectro){ * * * -* @Author: Juan Pedro Cobos Carrascosa (IAA-CSIC) +* @Author: Juan Pedro Cobos Carrascosa (IAA-CSIC) * jpedro@iaa.es * @Date: Nov. 2011 * @@ -903,59 +941,244 @@ void estimacionesClasicas(PRECISION lambda_0,double *lambda,int nlambda,PRECISIO PRECISION L,m,gamma, gamma_rad,tan_gamma,maxV,minV,C,maxWh,minWh; int i,j; + + //Es necesario crear un lambda en FLOAT para probar como se hace en la FPGA + PRECISION *lambda_aux; + lambda_aux= (PRECISION*) calloc(nlambda,sizeof(PRECISION)); + PRECISION lambda0,lambda1,lambda2,lambda3,lambda4; + + lambda0 = 6.1732012e+3 + 0; // RTE_WL_0 + lambda1 = lambda0 + 0.070000000; //RTE_WL_STEP + lambda2 = lambda1 + 0.070000000; + lambda3 = lambda2 + 0.070000000; + lambda4 = lambda3 + 0.070000000; + + lambda_aux[0]=lambda0; + lambda_aux[1]=lambda1; + lambda_aux[2]=lambda2; + lambda_aux[3]=lambda3; + lambda_aux[4]=lambda4; + + //Sino queremos usar el lambda de la FPGA + for(i=0;i1e-15) LM_lambda_plus = x / y; else LM_lambda_plus = 0; - + // LM_lambda_plus = x / y; x=0; y=0; for(i=0;i1e-15) LM_lambda_minus = x / y; else LM_lambda_minus = 0; + // LM_lambda_minus = x / y; C = (CTE4_6_13 * lambda_0 * lambda_0 * cuantic->GEFF); beta_B = 1 / C; - Blos = beta_B * ((LM_lambda_plus - LM_lambda_minus)/2); - Vlos = ( VLIGHT / lambda_0) * ((LM_lambda_plus + LM_lambda_minus)/2); - - - - Blos=Blos ; //factor de correción x campo debil - Vlos = Vlos ; //factor de correción ... + // printf("beta_B %20.12e \n",beta_B/2); + // printf("beta_v %20.12e \n",( VLIGHT / (lambda_0))/2); + // printf("cuantic->GEFF %f \n",cuantic->GEFF); + // exit(-1); - //inclinacion + Blos = beta_B * ((LM_lambda_plus - LM_lambda_minus)/2); + Vlos = ( VLIGHT / (lambda_0)) * ((LM_lambda_plus + LM_lambda_minus)/2); + + + //------------------------------------------------------------------------------------------------------------ + // //Para test del modo "non-polarimetric" --> Calculo de Vlos solo con I + + // x=0; + // y=0; + // for(i=0;i1e-12) + // // LM_lambda_plus = x / y; + // // else + // // LM_lambda_plus = 0; + // + // Vlos = ( VLIGHT / (lambda_0)) * ((LM_lambda_plus)); + + //------------------------------------------------------------------------------------------------------------ + + + //------------------------------------------------------------------------------------------------------------ + // //Para test del modo "Longitudinal" --> Calculo de Blos y Vlos solo con I+V y I-V + // //Los datos vienen en la forma de siempre salvo que spectroI contiene I+V y spectroV contiene I-V + // + // //Para usar los mismos perfiles de siempre es necesario tunearlos y convertirlos a I+V y I-V + // for(i=0;i1e-12) + // // LM_lambda_plus = x / y; + // // else + // // LM_lambda_plus = 0; + // + // + // x=0; + // y=0; + // for(i=0;i1e-12) + // // LM_lambda_minus = x / y; + // // else + // // LM_lambda_minus = 0; + // + // + // C = ((float)CTE4_6_13 * (float)lambda_0 * (float)lambda_0 * (float)cuantic->GEFF); + // beta_B = 1 / C; + // + // // printf("beta_B %20.12e \n",(float)beta_B/2); + // // printf("beta_B (no float cast) %20.12e \n",((1/(CTE4_6_13 * lambda_0 * lambda_0 * cuantic->GEFF))/2)); + // // printf("beta_v %20.12e \n",(float)(( (float)VLIGHT / ((float)lambda_0))/2)); + // // printf("cuantic->GEFF %f \n",cuantic->GEFF); + // // exit(-1); + // + // Blos = beta_B * ((LM_lambda_plus - LM_lambda_minus)/2); + // Vlos = ( VLIGHT / (lambda_0)) * ((LM_lambda_plus + LM_lambda_minus)/2); + // + // // printf("spectroI_0 %20.7e \n",(float)spectroI[0]); + // // printf("spectroI_1 %20.7e \n",(float)spectroI[1]); + // // printf("spectroI_2 %20.7e \n",(float)spectroI[2]); + // // printf("spectroI_3 %20.7e \n",(float)spectroI[3]); + // // printf("spectroI_4 %20.7e \n",(float)spectroI[4]); + // // printf("spectroI_5 %20.7e \n",(float)spectroI[5]); + // // printf("Blos %20.12e \n",(float)Blos); + // // printf("Vlos %20.12e \n",(float)Vlos); + // // + // // exit(-1); + //------------------------------------------------------------------------------------------------------------ + + //------------------------------------------------------------------------------------------------------------ + // //Para probar fórmulación propuesta por D. Orozco (Junio 2017) + //La formula es la 2.7 que proviene del paper: + // Diagnostics for spectropolarimetry and magnetography by Jose Carlos del Toro Iniesta and Valent´ýn Mart´ýnez Pillet + //el 0.08 Es la anchura de la línea en lugar de la resuloción del etalón. + + //Vlos = ( 2*(VLIGHT)*0.08 / (PI*lambda_0)) * atan((spectroI[0]+spectroI[1]-spectroI[3]-spectroI[4])/(spectroI[0]-spectroI[1]-spectroI[3]+spectroI[4])); + + //------------------------------------------------------------------------------------------------------------ + + + Blos=Blos*1 ; //factor de correción x campo debil + Vlos = Vlos * 1 ; //factor de correción ... + + //inclinacion x = 0; y = 0; for(i=0;i 1e-7 ? x : 0; + // y = fabs(y) > 1e-7 ? y : 0; + + tan_gamma = fabs(sqrtf(x/y)); + + // tan_gamma = fabs(tan_gamma) > 1e-7 ? tan_gamma : 0; + gamma_rad = atan(tan_gamma); //gamma en radianes - - gamma = gamma_rad * (180/ PI); //gamma en grados + // if(sqrt(y)<1e-12) + // gamma_rad = PI/2; + // else + // gamma_rad = atan2(sqrt(x),sqrt(y)); //gamma en radianes + + //gamma_rad = atan(sqrtf(x),y)); //gamma en radianes + + // gamma_rad = fabs(gamma_rad) > 1e-7 ? gamma_rad : 0; + + gamma = gamma_rad * (180/ PI); //gamma en grados - //correccion + //correccion //utilizamos el signo de Blos para ver corregir el cuadrante + PRECISION gamma_out = gamma; + if (Blos<0) - gamma = 180-gamma; - - + gamma = (180)-gamma; + + + //azimuth PRECISION tan2phi,phi; int muestra; - + if(nlambda==6) muestra = CLASSICAL_ESTIMATES_SAMPLE_REF; else muestra = nlambda*0.75; - - + + tan2phi=spectroU[muestra]/spectroQ[muestra]; -// printf("tan2phi : %f \n",tan2phi); + // printf("tan2phi : %f \n",tan2phi); + // printf("%.10e \n",spectroU[muestra]); + // printf("%.10e \n",spectroQ[muestra]); - phi= (atan(tan2phi)*180/PI) / 2; -// printf("atan : %f \n",phi*2); - + phi= (atan(tan2phi)*180/PI) / 2; //atan con paso a grados + + //printf("atan : %f \n",phi*2); + + // printf("%.10e \n",atan(tan2phi)); + if(spectroU[muestra] > 0 && spectroQ[muestra] > 0 ) phi=phi; - else + else if (spectroU[muestra] < 0 && spectroQ[muestra] > 0 ) phi=phi + 180; else if (spectroU[muestra] < 0 && spectroQ[muestra] < 0 ) phi=phi + 90; - else + else if (spectroU[muestra] > 0 && spectroQ[muestra]< 0 ) phi=phi + 90; - + // printf("%.10e \n",phi); //printf("Blos : %f \n",Blos); //printf("vlos : %f \n",Vlos); @@ -1018,25 +1265,32 @@ void estimacionesClasicas(PRECISION lambda_0,double *lambda,int nlambda,PRECISIO PRECISION B_aux; - - B_aux = fabs(Blos/cos(gamma_rad));//*2; - - if(Vlos < (-5)) - Vlos= -5; - if(Vlos >(5)) - Vlos=(5); - - if(phi< 0) - phi = 180 + (phi); - if(phi > 180){ - phi = phi -180.0; - } - + B_aux = fabs(Blos/cos(gamma_rad)) * 2; // 2 factor de corrección + + //Vlos = Vlos * 1.5; + if(Vlos < (-20)) + Vlos= -20; + if(Vlos >(20)) + Vlos=(20); + + // if(phi< 0) + // phi = 180 + (phi); + // if(phi > 180){ + // phi = phi -180.0; + // } + + // printf("%.10e \n",phi); + initModel->B = (B_aux>4000?4000:B_aux); initModel->vlos=Vlos;//(Vlos*1.5);//1.5; initModel->gm=gamma; initModel->az=phi; + initModel->S0= Blos; + + + //Liberar memoria del vector de lambda auxiliar + free(lambda_aux); } @@ -1056,35 +1310,46 @@ void AplicaDelta(Init_Model *model,PRECISION * delta,int * fixed,Init_Model *mod if(fixed[0]){ modelout->eta0=model->eta0-delta[0]; // 0 - } + } if(fixed[1]){ if(delta[1]< -800) //300 delta[1]=-800; else if(delta[1] >800) delta[1]=800; - modelout->B=model->B-delta[1];//magnetic field + modelout->B=model->B-delta[1];//magnetic field } if(fixed[2]){ - - if(delta[2]>5) - delta[2] = 5; - if(delta[2]<-5) - delta[2] = -5; + if(delta[2]>2) + delta[2] = 2; + + if(delta[2]<-2) + delta[2] = -2; modelout->vlos=model->vlos-delta[2]; } - if(fixed[3]) + + if(fixed[3]){ + + if(delta[3]>1e-2) + delta[3] = 1e-2; + else + if(delta[3]<-1e-2) + delta[3] = -1e-2; + modelout->dopp=model->dopp-delta[3]; + } + if(fixed[4]) modelout->aa=model->aa-delta[4]; + if(fixed[5]){ - if(delta[5]< -45) //15 - delta[5]=-45; + if(delta[5]< -15) //15 + delta[5]=-15; else - if(delta[5] > 45) - delta[5]=45; + if(delta[5] > 15) + delta[5]=15; modelout->gm=model->gm-delta[5]; //5 } @@ -1093,7 +1358,7 @@ void AplicaDelta(Init_Model *model,PRECISION * delta,int * fixed,Init_Model *mod delta[6]=-15; else if(delta[6] > 15) - delta[6]=15; + delta[6]= 15; modelout->az=model->az-delta[6]; } @@ -1120,14 +1385,14 @@ int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta){ static PRECISION v2[TAMANIO_SVD][TAMANIO_SVD],w2[TAMANIO_SVD],v[NTERMS*NTERMS],w[NTERMS]; static PRECISION h1[NTERMS*NTERMS],h_svd[TAMANIO_SVD*TAMANIO_SVD]; static PRECISION aux[NTERMS*NTERMS]; - int i,j,j1; + int i,j; // static double aux2[NTERMS*NTERMS]; static PRECISION aux2[NTERMS]; int aux_nf,aux_nc; PRECISION factor,maximo,minimo; int posi,posj; - epsilon= 1e-15; + epsilon= 1e-12; top=1.0; factor=0; @@ -1139,29 +1404,45 @@ int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta){ for(j=0;jmaximo){ + if(fabs(h[j])>maximo){ maximo=fabs(h[j]); } } factor=maximo; - + + //printf("maximo : %.12e \n",maximo); + //exit(-1); + + if(!NORMALIZATION_SVD) factor = 1; for(j=0;j epsilon) ? (1/waux[i]) : 0.0); + aux2[i]= aux2[i]*((fabs(waux[i]) > epsilon) ? (1/waux[i]): 0.0);//((waux[i]>0)?(1/epsilon):(-1/epsilon))); //(1/waux[i]) : 0);// +// aux2[i]= aux2[i]*((fabs(waux[i]) > epsilon) ? (1/waux[i]): (1/epsilon));//((waux[i]>0)?(1/epsilon):(-1/epsilon))); //(1/waux[i]) : 0);// } multmatrix(vaux,NTERMS,NTERMS,aux2,NTERMS,1,delta,&aux_nf,&aux_nc); +/* + printf("\n"); + printf("#################################### delta \n"); + int j1; + for(j1=0;j1gm < 0) model->gm = -(model->gm); if(model->gm > 180) model->gm =180-(((int)floor(model->gm) % 180)+(model->gm-floor(model->gm)));//180-((int)model->gm % 180);*/ - - - //Magnetic field + + //Magnetic field if(model->B < 0){ - model->B = -(model->B); - model->gm = 180.0 -(model->gm); - } + //model->B = 190; + model->B = -(model->B); + model->gm = 180.0 -(model->gm); + } if(model->B > 5000) - model->B= 5000; - + model->B= 5000; + + //Inclination if(model->gm < 0) model->gm = -(model->gm); - if(model->gm > 180) - model->gm = 360.0 - model->gm; + if(model->gm > 180){ + model->gm = 360.0 - model->gm; + // model->gm = 179; //360.0 - model->gm; + } //azimuth if(model->az < 0) - model->az= 180 + (model->az); + model->az= 180 + (model->az); //model->az= 180 + (model->az); if(model->az > 180){ model->az =model->az -180.0; + // model->az = 179.0; } //RANGOS //Eta0 if(model->eta0 < 0.1) model->eta0=0.1; - if(model->eta0 >8) - model->eta0=8; - + + // if(model->eta0 >8) + // model->eta0=8; + if(model->eta0 >2500) //idl 2500 + model->eta0=2500; + //velocity - if(model->vlos < (-5)) //20 - model->vlos= (-5); - if(model->vlos >5) - model->vlos=5; + if(model->vlos < (-20)) //20 + model->vlos= (-20); + if(model->vlos >20) + model->vlos=20; //doppler width ;Do NOT CHANGE THIS if(model->dopp < 0.0001) model->dopp = 0.0001; - - if(model->dopp > 0.800) - model->dopp = 0.800; - - if(model->aa < 0.00001) - model->aa = 0.00001; - if(model->aa > 10) + if(model->dopp > 1.6) // idl 0.6 + model->dopp = 1.6; + + + if(model->aa < 0.0001) // idl 1e-4 + model->aa = 0.0001; + if(model->aa > 10) //10 model->aa = 10; - + //S0 if(model->S0 < 0.0001) model->S0 = 0.0001; - if(model->S0 > 2.000) - model->S0 = 2.000; + if(model->S0 > 1.500) + model->S0 = 1.500; //S1 if(model->S1 < 0.0001) model->S1 = 0.0001; if(model->S1 > 2.000) model->S1 = 2.000; - + //macroturbulence if(model->mac < 0) model->mac = 0; if(model->mac > 4) model->mac = 4; - + //filling factor /* if(model->S1 < 0) model->S1 = 0; if(model->S1 > 1) model->S1 = 1;*/ - + return 1; } - - - - void spectral_synthesis_convolution(){ - + int i; int nlambda=NLAMBDA; - + //convolucionamos los perfiles IQUV (spectra) if(INSTRUMENTAL_CONVOLUTION){ - + PRECISION Ic; - - - + + if(!INSTRUMENTAL_CONVOLUTION_INTERPOLACION){ //convolucion de I Ic=spectra[nlambda-1]; - + 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 literal 0 HcmV?d00001 diff --git a/cmilos-fits/milos_David.c b/cmilos-fits/milos_David.c new file mode 100644 index 0000000..33fb479 --- /dev/null +++ b/cmilos-fits/milos_David.c @@ -0,0 +1,1206 @@ + +// _______ _______ _________ _ _______ _______ +// ( ____ \ ( )\__ __/( \ ( ___ )( ____ \ +// | ( \/ | () () | ) ( | ( | ( ) || ( \/ +// | | _____ | || || | | | | | | | | || (_____ +// | | (_____) | |(_)| | | | | | | | | |(_____ ) +// | | | | | | | | | | | | | | ) | +// | (____/\ | ) ( |___) (___| (____/\| (___) |/\____) | +// (_______/ |/ \|\_______/(_______/(_______)\_______) +// +// +// CMILOS v0.9 (2015) +// RTE INVERSION C code for SOPHI (based on the ILD code MILOS by D. Orozco) +// juanp (IAA-CSIC) +// +// How to use: +// +// >> milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES [FWHM DELTA NPOINTS] profiles_file.txt > output.txt +// +// NLAMBDA number of lambda of input profiles +// MAX_ITER of inversion +// CLASSICAL_ESTIMATES use classical estimates? 1 yes, 0 no +// [FWHM DELTA NPOINTS] use convolution with a gaussian? if the tree parameteres are defined yes, else no. Units in A. NPOINTS has to be odd. +// profiles_file.txt name of input profiles file +// output.txt name of output file +// +// + +#include "defines.h" + +#include "nrutil.h" +#include "svdcmp.c" +#include "svdcordic.c" +//#include "tridiagonal.c" +#include "convolution.c" + +#include + +float pythag(float a, float b); + +void weights_init(int nlambda,double *sigma,PRECISION *weight,int nweight,PRECISION **wOut,PRECISION **sigOut,double noise); + +int check(Init_Model *Model); +int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlambda,PRECISION *spectro,int nspectro, + Init_Model *initModel, PRECISION *spectra,int err,double *chisqrf, int *iterOut, + double slight, double toplim, int miter, PRECISION * weight,int nweight, int * fix, + PRECISION *sigma, double filter, double ilambda, double noise, double *pol, + double getshi,int triplete); + +int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta); + +int multmatrixIDL(double *a,int naf,int nac, double *b,int nbf,int nbc,double **resultOut,int *fil,int *col); +int multmatrix_transposeD(double *a,int naf,int nac, double *b,int nbf,int nbc,double *result,int *fil,int *col); +int multmatrix3(PRECISION *a,int naf,int nac,double *b,int nbf,int nbc,double **result,int *fil,int *col); +double * leeVector(char *nombre,int tam); +double * transpose(double *mat,int fil,int col); + +double total(double * A, int f,int c); +int multmatrix(PRECISION *a,int naf,int nac, PRECISION *b,int nbf,int nbc,PRECISION *result,int *fil,int *col); +int multmatrix2(double *a,int naf,int nac, PRECISION *b,int nbf,int nbc,double **result,int *fil,int *col); + +int covarm(PRECISION *w,PRECISION *sig,int nsig,PRECISION *spectro,int nspectro,PRECISION *spectra,PRECISION *d_spectra, + PRECISION *beta,PRECISION *alpha); + +int CalculaNfree(PRECISION *spectro,int nspectro); + +double fchisqr(PRECISION * spectra,int nspectro,PRECISION *spectro,PRECISION *w,PRECISION *sig,double nfree); + +void AplicaDelta(Init_Model *model,PRECISION * delta,int * fixed,Init_Model *modelout); +void FijaACeroDerivadasNoNecesarias(PRECISION * d_spectra,int *fixed,int nlambda); +void reformarVector(PRECISION **spectro,int neje); +void spectral_synthesis_convolution(); +void response_functions_convolution(); + +void estimacionesClasicas(PRECISION lambda_0,double *lambda,int nlambda,PRECISION *spectro,Init_Model *initModel); + +#define tiempo(ciclos) asm volatile ("rdtsc \n\t":"=A"(ciclos)) +long long int c1,c2,cd,semi,c1a,c2a,cda; //variables de 64 bits para leer ciclos de reloj +long long int c1total,c2total,cdtotal,ctritotal; + + +Cuantic* cuantic; // Variable global, está hecho así, de momento,para parecerse al original +char * concatena(char *a, int n,char*b); + +PRECISION ** PUNTEROS_CALCULOS_COMPARTIDOS; +int POSW_PUNTERO_CALCULOS_COMPARTIDOS; +int POSR_PUNTERO_CALCULOS_COMPARTIDOS; + +PRECISION * gp1,*gp2,*dt,*dti,*gp3,*gp4,*gp5,*gp6,*etai_2; + +//PRECISION gp4_gp2_rhoq[NLAMBDA],gp5_gp2_rhou[NLAMBDA],gp6_gp2_rhov[NLAMBDA]; +PRECISION *gp4_gp2_rhoq,*gp5_gp2_rhou,*gp6_gp2_rhov; + + +PRECISION *dgp1,*dgp2,*dgp3,*dgp4,*dgp5,*dgp6,*d_dt; +PRECISION * d_ei,*d_eq,*d_eu,*d_ev,*d_rq,*d_ru,*d_rv; +PRECISION *dfi,*dshi; +PRECISION CC,CC_2,sin_gm,azi_2,sinis,cosis,cosis_2,cosi,sina,cosa,sinda,cosda,sindi,cosdi,sinis_cosa,sinis_sina; +PRECISION *fi_p,*fi_b,*fi_r,*shi_p,*shi_b,*shi_r; +PRECISION *etain,*etaqn,*etaun,*etavn,*rhoqn,*rhoun,*rhovn; +PRECISION *etai,*etaq,*etau,*etav,*rhoq,*rhou,*rhov; +PRECISION *parcial1,*parcial2,*parcial3; +PRECISION *nubB,*nupB,*nurB; +PRECISION **uuGlobalInicial; +PRECISION **HGlobalInicial; +PRECISION **FGlobalInicial; +PRECISION *perfil_instrumental; +PRECISION * G; +int FGlobal,HGlobal,uuGlobal; + +PRECISION *d_spectra,*spectra; + +//Number of lambdas in the input profiles +int NLAMBDA = 0; + +//Convolutions values +int NMUESTRAS_G = 0; +PRECISION FWHM = 0; +PRECISION DELTA = 0; + +int INSTRUMENTAL_CONVOLUTION = 0; +int CLASSICAL_ESTIMATES = 0; +int RFS = 0; + + +int main(int argc,char **argv){ + + double * wlines; + int nwlines; + double *lambda; + int nlambda; + PRECISION *spectro; + int ny,i,j; + Init_Model initModel; + int err; + double chisqrf; + int iter; + double slight; + double toplim; + int miter; + PRECISION weight[4]={1.,1.,1.,1.}; + int nweight; + + // CONFIGURACION DE PARAMETROS A INVERTIR + //INIT_MODEL=[eta0,magnet,vlos,landadopp,aa,gamma,azi,B1,B2,macro,alfa] + int fix[]={1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.}; //Parametros invertidos + //---------------------------------------------- + + double sigma[NPARMS]; + double vsig; + double filter; + double ilambda; + double noise; + double *pol; + double getshi; + + double dat[7]={CUANTIC_NWL,CUANTIC_SLOI,CUANTIC_LLOI,CUANTIC_JLOI,CUANTIC_SUPI,CUANTIC_LUPI,CUANTIC_JUPI}; + + char *nombre,*input_iter; + int Max_iter; + + //milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES RFS [FWHM DELTA NPOINTS] perfil.txt + + if(argc!=4 && argc!=5 && argc !=8 ){ // changed argc !=8 to !=9 (for RF output) + printf("milos: Error en el numero de parametros: %d .\n Pruebe: milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES RFS [FWHM(in A) DELTA(in A) NPOINTS] perfil.txt\n",argc); + return -1; + } + + NLAMBDA = atoi(argv[1]); + + input_iter = argv[2]; + Max_iter = atoi(input_iter); + CLASSICAL_ESTIMATES = atoi(argv[3]); + + if(CLASSICAL_ESTIMATES!=0 && CLASSICAL_ESTIMATES != 1){ + printf("milos: Error in CLASSICAL_ESTIMATES parameter. 0 or 1 are valid values. Not accepted: \n",CLASSICAL_ESTIMATES); + return -1; + } + + if(argc ==5){ + nombre = argv[4]; + } + else if(argc == 6) { //DOS + RFS = 1; + } + else { + INSTRUMENTAL_CONVOLUTION = 1; + NMUESTRAS_G = atoi(argv[6]); + FWHM = atof(argv[4]); + DELTA = atof(argv[5]); + nombre = argv[7]; + } + + + //Generamos la gaussiana -> perfil instrumental + if(INSTRUMENTAL_CONVOLUTION){ + G=vgauss(FWHM,NMUESTRAS_G,DELTA); + + //if you wish to convolution with other instrumental profile you have to declare here and to asign it to "G" + } + + + cuantic=create_cuantic(dat); + Inicializar_Puntero_Calculos_Compartidos(); + + toplim=1e-18; + + CC=PI/180.0; + CC_2=CC*2; + + filter=0; + getshi=0; + nweight=4; + + nwlines=1; + wlines=(double*) calloc(2,sizeof(double)); + wlines[0]=1; + wlines[1]= CENTRAL_WL; + + vsig=NOISE_SIGMA; //original 0.001 + sigma[0]=vsig; + sigma[1]=vsig; + sigma[2]=vsig; + sigma[3]=vsig; + pol=NULL; + + noise=NOISE_SIGMA; + ilambda=ILAMBDA; + iter=0; + miter=Max_iter; + + nlambda=NLAMBDA; + lambda=calloc(nlambda,sizeof(double)); + spectro=calloc(nlambda*4,sizeof(PRECISION)); + + FILE *fichero, *fichero_estimacioneClasicas; + + fichero= fopen(nombre,"r"); + if(fichero==NULL){ + printf("Error de apertura, es posible que el fichero no exista.\n"); + printf("Milos: Error de lectura del fichero. ++++++++++++++++++\n"); + return 1; + } + + char * buf; + buf=calloc(strlen(nombre)+15,sizeof(char)); + buf = strcat(buf,nombre); + buf = strcat(buf,"_CL_ESTIMATES"); + + if(CLASSICAL_ESTIMATES){ + fichero_estimacioneClasicas= fopen(buf,"w"); + if(fichero_estimacioneClasicas==NULL){ + printf("Error de apertura ESTIMACIONES CLASICAS, es posible que el fichero no exista.\n"); + printf("Milos: Error de lectura del fichero. ++++++++++++++++++\n"); + return 1; + } + } + int neje; + double lin; + double iin,qin,uin,vin; + int rfscanf; + int contador; + + int totalIter=0; + + contador=0; + + ReservarMemoriaSinteisisDerivadas(nlambda); + + //initializing weights + PRECISION *w,*sig; + weights_init(nlambda,sigma,weight,nweight,&w,&sig,noise); + + c2total=0; + ctritotal=0; + + int nsub,indaux; + indaux=0; + + + + do{ + neje=0; + nsub=0; + while (nejegms de initmodel + nfree=CalculaNfree(spectro,nspectro); + //printf("\n nfree! %d:\n",nfree); + //exit(-1); + + + if(nfree==0){ + return -1; //'NOT ENOUGH POINTS' + } + + flambda=ilambda; + + if(fix==NULL){ + fixed=calloc(NTERMS,sizeof(double)); + for(i=0;iGEFF); + beta_B = 1 / C; + + Blos = beta_B * ((LM_lambda_plus - LM_lambda_minus)/2); + Vlos = ( VLIGHT / lambda_0) * ((LM_lambda_plus + LM_lambda_minus)/2); + + + + Blos=Blos ; //factor de correción x campo debil + Vlos = Vlos ; //factor de correción ... + + //inclinacion + x = 0; + y = 0; + for(i=0;i 0 && spectroQ[muestra] > 0 ) + phi=phi; + else + if (spectroU[muestra] < 0 && spectroQ[muestra] > 0 ) + phi=phi + 180; + else + if (spectroU[muestra] < 0 && spectroQ[muestra] < 0 ) + phi=phi + 90; + else + if (spectroU[muestra] > 0 && spectroQ[muestra]< 0 ) + phi=phi + 90; + + + + //printf("Blos : %f \n",Blos); + //printf("vlos : %f \n",Vlos); + //printf("gamma : %f \n",gamma); + //printf("phi : %f \n",phi); + + + PRECISION B_aux; + + B_aux = fabs(Blos/cos(gamma_rad));//*2; + + + if(Vlos < (-5)) + Vlos= -5; + if(Vlos >(5)) + Vlos=(5); + + if(phi< 0) + phi = 180 + (phi); + if(phi > 180){ + phi = phi -180.0; + } + + initModel->B = (B_aux>4000?4000:B_aux); + initModel->vlos=Vlos;//(Vlos*1.5);//1.5; + initModel->gm=gamma; + initModel->az=phi; + +} + +void FijaACeroDerivadasNoNecesarias(PRECISION * d_spectra,int *fixed,int nlambda){ + + int In,j,i; + for(In=0;Ineta0=model->eta0-delta[0]; // 0 + } + if(fixed[1]){ + if(delta[1]< -800) //300 + delta[1]=-800; + else + if(delta[1] >800) + delta[1]=800; + modelout->B=model->B-delta[1];//magnetic field + } + if(fixed[2]){ + + if(delta[2]>5) + delta[2] = 5; + + if(delta[2]<-5) + delta[2] = -5; + + modelout->vlos=model->vlos-delta[2]; + } + if(fixed[3]) + modelout->dopp=model->dopp-delta[3]; + if(fixed[4]) + modelout->aa=model->aa-delta[4]; + if(fixed[5]){ + if(delta[5]< -45) //15 + delta[5]=-45; + else + if(delta[5] > 45) + delta[5]=45; + + modelout->gm=model->gm-delta[5]; //5 + } + if(fixed[6]){ + if(delta[6]< -15) + delta[6]=-15; + else + if(delta[6] > 15) + delta[6]=15; + + modelout->az=model->az-delta[6]; + } + if(fixed[7]) + modelout->S0=model->S0-delta[7]; + if(fixed[8]) + modelout->S1=model->S1-delta[8]; + if(fixed[9]) + modelout->mac=model->mac-delta[9]; //9 + if(fixed[10]) + modelout->alfa=model->alfa-delta[10]; +} + +/* + Tamaño de H es NTERMS x NTERMS + Tamaño de beta es 1xNTERMS + + return en delta tam 1xNTERMS +*/ + +int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta){ + + double epsilon,top; + static PRECISION v2[TAMANIO_SVD][TAMANIO_SVD],w2[TAMANIO_SVD],v[NTERMS*NTERMS],w[NTERMS]; + static PRECISION h1[NTERMS*NTERMS],h_svd[TAMANIO_SVD*TAMANIO_SVD]; + static PRECISION aux[NTERMS*NTERMS]; + int i,j,j1; +// static double aux2[NTERMS*NTERMS]; + static PRECISION aux2[NTERMS]; + int aux_nf,aux_nc; + PRECISION factor,maximo,minimo; + int posi,posj; + + epsilon= 1e-15; + top=1.0; + + factor=0; + maximo=0; + minimo=1000000000; + + + /**/ + for(j=0;jmaximo){ + maximo=fabs(h[j]); + } + } + + factor=maximo; + + if(!NORMALIZATION_SVD) + factor = 1; + + for(j=0;j epsilon) ? (1/waux[i]) : 0.0); + } + + multmatrix(vaux,NTERMS,NTERMS,aux2,NTERMS,1,delta,&aux_nf,&aux_nc); + + return 1; + +} + + + +void weights_init(int nlambda,double *sigma,PRECISION *weight,int nweight,PRECISION **wOut,PRECISION **sigOut,double noise) +{ + int i,j; + PRECISION *w,*sig; + + + sig=calloc(4,sizeof(PRECISION)); + if(sigma==NULL){ + for(i=0;i<4;i++) + sig[i]= noise* noise; + } + else{ + + for(i=0;i<4;i++) + sig[i]= (*sigma);// * (*sigma); + } + + *wOut=w; + *sigOut=sig; + +} + + +int check(Init_Model *model){ + + double offset=0; + double inter; + + + + + //Inclination + /* if(model->gm < 0) + model->gm = -(model->gm); + if(model->gm > 180) + model->gm =180-(((int)floor(model->gm) % 180)+(model->gm-floor(model->gm)));//180-((int)model->gm % 180);*/ + + + //Magnetic field + if(model->B < 0){ + model->B = -(model->B); + model->gm = 180.0 -(model->gm); + } + if(model->B > 5000) + model->B= 5000; + + if(model->gm < 0) + model->gm = -(model->gm); + if(model->gm > 180) + model->gm = 360.0 - model->gm; + + //azimuth + if(model->az < 0) + model->az= 180 + (model->az); + if(model->az > 180){ + model->az =model->az -180.0; + } + + //RANGOS + //Eta0 + if(model->eta0 < 0.1) + model->eta0=0.1; + if(model->eta0 >8) + model->eta0=8; + + //velocity + if(model->vlos < (-5)) //20 + model->vlos= (-5); + if(model->vlos >5) + model->vlos=5; + + //doppler width ;Do NOT CHANGE THIS + if(model->dopp < 0.0001) + model->dopp = 0.0001; + + if(model->dopp > 0.800) + model->dopp = 0.800; + + + if(model->aa < 0.00001) + model->aa = 0.00001; + if(model->aa > 10) + model->aa = 10; + + //S0 + if(model->S0 < 0.0001) + model->S0 = 0.0001; + if(model->S0 > 2.000) + model->S0 = 2.000; + + //S1 + if(model->S1 < 0.0001) + model->S1 = 0.0001; + if(model->S1 > 2.000) + model->S1 = 2.000; + + //macroturbulence + if(model->mac < 0) + model->mac = 0; + if(model->mac > 4) + model->mac = 4; + + //filling factor +/* if(model->S1 < 0) + model->S1 = 0; + if(model->S1 > 1) + model->S1 = 1;*/ + + return 1; +} + + + + + +void spectral_synthesis_convolution(){ + + int i; + int nlambda=NLAMBDA; + + //convolucionamos los perfiles IQUV (spectra) + if(INSTRUMENTAL_CONVOLUTION){ + + PRECISION Ic; + + + + if(!INSTRUMENTAL_CONVOLUTION_INTERPOLACION){ + //convolucion de I + Ic=spectra[nlambda-1]; + + for(i=0;i> milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES [FWHM DELTA NPOINTS] profiles_file.txt > output.txt +// +// NLAMBDA number of lambda of input profiles +// MAX_ITER of inversion +// CLASSICAL_ESTIMATES use classical estimates? 1 yes, 0 no +// [FWHM DELTA NPOINTS] use convolution with a gaussian? if the tree parameteres are defined yes, else no. Units in A. NPOINTS has to be odd. +// profiles_file.txt name of input profiles file +// output.txt name of output file +// +// + +#include +#include "defines.h" + +#include "nrutil.h" +#include "svdcmp.c" +#include "svdcordic.c" +//#include "tridiagonal.c" +#include "convolution.c" + +#include + +float pythag(float a, float b); + +void weights_init(int nlambda,double *sigma,PRECISION *weight,int nweight,PRECISION **wOut,PRECISION **sigOut,double noise); + +int check(Init_Model *Model); +int lm_mils(Cuantic *cuantic,double * wlines,int nwlines,double *lambda,int nlambda,PRECISION *spectro,int nspectro, + Init_Model *initModel, PRECISION *spectra,int err,double *chisqrf, int *iterOut, + double slight, double toplim, int miter, PRECISION * weight,int nweight, int * fix, + PRECISION *sigma, double filter, double ilambda, double noise, double *pol, + double getshi,int triplete); + +int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta); + +int multmatrixIDL(double *a,int naf,int nac, double *b,int nbf,int nbc,double **resultOut,int *fil,int *col); +int multmatrix_transposeD(double *a,int naf,int nac, double *b,int nbf,int nbc,double *result,int *fil,int *col); +int multmatrix3(PRECISION *a,int naf,int nac,double *b,int nbf,int nbc,double **result,int *fil,int *col); +double * leeVector(char *nombre,int tam); +double * transpose(double *mat,int fil,int col); + +double total(double * A, int f,int c); +int multmatrix(PRECISION *a,int naf,int nac, PRECISION *b,int nbf,int nbc,PRECISION *result,int *fil,int *col); +int multmatrix2(double *a,int naf,int nac, PRECISION *b,int nbf,int nbc,double **result,int *fil,int *col); + +int covarm(PRECISION *w,PRECISION *sig,int nsig,PRECISION *spectro,int nspectro,PRECISION *spectra,PRECISION *d_spectra, + PRECISION *beta,PRECISION *alpha); + +int CalculaNfree(PRECISION *spectro,int nspectro); + +double fchisqr(PRECISION * spectra,int nspectro,PRECISION *spectro,PRECISION *w,PRECISION *sig,double nfree); + +void AplicaDelta(Init_Model *model,PRECISION * delta,int * fixed,Init_Model *modelout); +void FijaACeroDerivadasNoNecesarias(PRECISION * d_spectra,int *fixed,int nlambda); +void reformarVector(PRECISION **spectro,int neje); +void spectral_synthesis_convolution(); +void response_functions_convolution(); + +void estimacionesClasicas(PRECISION lambda_0,double *lambda,int nlambda,PRECISION *spectro,Init_Model *initModel); + +#define tiempo(ciclos) asm volatile ("rdtsc \n\t":"=A"(ciclos)) +long long int c1,c2,cd,semi,c1a,c2a,cda; //variables de 64 bits para leer ciclos de reloj +long long int c1total,c2total,cdtotal,ctritotal; + + +Cuantic* cuantic; // Variable global, está hecho así, de momento,para parecerse al original +char * concatena(char *a, int n,char*b); + +PRECISION ** PUNTEROS_CALCULOS_COMPARTIDOS; +int POSW_PUNTERO_CALCULOS_COMPARTIDOS; +int POSR_PUNTERO_CALCULOS_COMPARTIDOS; + +PRECISION * gp1,*gp2,*dt,*dti,*gp3,*gp4,*gp5,*gp6,*etai_2; + +//PRECISION gp4_gp2_rhoq[NLAMBDA],gp5_gp2_rhou[NLAMBDA],gp6_gp2_rhov[NLAMBDA]; +PRECISION *gp4_gp2_rhoq,*gp5_gp2_rhou,*gp6_gp2_rhov; + + +PRECISION *dgp1,*dgp2,*dgp3,*dgp4,*dgp5,*dgp6,*d_dt; +PRECISION * d_ei,*d_eq,*d_eu,*d_ev,*d_rq,*d_ru,*d_rv; +PRECISION *dfi,*dshi; +PRECISION CC,CC_2,sin_gm,azi_2,sinis,cosis,cosis_2,cosi,sina,cosa,sinda,cosda,sindi,cosdi,sinis_cosa,sinis_sina; +PRECISION *fi_p,*fi_b,*fi_r,*shi_p,*shi_b,*shi_r; +PRECISION *etain,*etaqn,*etaun,*etavn,*rhoqn,*rhoun,*rhovn; +PRECISION *etai,*etaq,*etau,*etav,*rhoq,*rhou,*rhov; +PRECISION *parcial1,*parcial2,*parcial3; +PRECISION *nubB,*nupB,*nurB; +PRECISION **uuGlobalInicial; +PRECISION **HGlobalInicial; +PRECISION **FGlobalInicial; +PRECISION *perfil_instrumental; +PRECISION * G; +int FGlobal,HGlobal,uuGlobal; + +PRECISION *d_spectra,*spectra; + +//Number of lambdas in the input profiles +int NLAMBDA = 0; + +//Convolutions values +int NMUESTRAS_G = 0; +PRECISION FWHM = 0; +PRECISION DELTA = 0; + +int INSTRUMENTAL_CONVOLUTION = 0; +int INSTRUMENTAL_CONVOLUTION_WITH_PSF = 0; +int CLASSICAL_ESTIMATES = 0; +int RFS = 0; + +const PRECISION crisp_psf[141] = {0.0004,0.0004,0.0005,0.0005,0.0005,0.0005,0.0006,0.0006,0.0006,0.0007,0.0007,0.0008,0.0008,0.0009,0.0009,0.0010,0.0010,0.0011,0.0012,0.0012,0.0013,0.0014, + 0.0015,0.0016,0.0017,0.0019,0.0020,0.0021,0.0023,0.0025,0.0027,0.0029,0.0031,0.0034,0.0037,0.0040,0.0044,0.0048,0.0052,0.0057,0.0062,0.0069,0.0076,0.0083, + 0.0092,0.0102,0.0114,0.0127,0.0142,0.0159,0.0178,0.0202,0.0229,0.0261,0.0299,0.0343,0.0398,0.0465,0.0546,0.0645,0.0765,0.0918,0.1113,0.1363,0.1678,0.2066, + 0.2501,0.2932,0.3306,0.3569,0.3669,0.3569,0.3306,0.2932,0.2501,0.2066,0.1678,0.1363,0.1113,0.0918,0.0765,0.0645,0.0546,0.0465,0.0398,0.0343,0.0299,0.0261, + 0.0229,0.0202,0.0178,0.0159,0.0142,0.0127,0.0114,0.0102,0.0092,0.0083,0.0076,0.0069,0.0062,0.0057,0.0052,0.0048,0.0044,0.0040,0.0037,0.0034,0.0031,0.0029, + 0.0027,0.0025,0.0023,0.0021,0.0020,0.0019,0.0017,0.0016,0.0015,0.0014,0.0013,0.0012,0.0012,0.0011,0.0010,0.0010,0.0009,0.0009,0.0008,0.0008,0.0007,0.0007, + 0.0006,0.0006,0.0006,0.0005,0.0005,0.0005,0.0005,0.0004,0.0004}; + + + + +int main(int argc,char **argv){ + + double * wlines; + int nwlines; + double *lambda; + int nlambda; + PRECISION *spectro; + int ny,i,j; + Init_Model initModel; + int err; + double chisqrf; + int iter; + double slight; + double toplim; + int miter; + PRECISION weight[4]={1.,1.,1.,1.}; + int nweight; + + clock_t t_ini, t_fin; + double secs, total_secs; + + + // CONFIGURACION DE PARAMETROS A INVERTIR + //INIT_MODEL=[eta0,magnet,vlos,landadopp,aa,gamma,azi,B1,B2,macro,alfa] + int fix[]={1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.}; //Parametros invertidos + //---------------------------------------------- + + double sigma[NPARMS]; + double vsig; + double filter; + double ilambda; + double noise; + double *pol; + double getshi; + + double dat[7]={CUANTIC_NWL,CUANTIC_SLOI,CUANTIC_LLOI,CUANTIC_JLOI,CUANTIC_SUPI,CUANTIC_LUPI,CUANTIC_JUPI}; + + char *nombre,*input_iter; + int Max_iter; + + //milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES RFS [FWHM DELTA NPOINTS] perfil.txt + + if(argc!=6 && argc != 7 && argc !=9){ + printf("milos: Error en el numero de parametros: %d .\n Pruebe: milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES RFS [FWHM(in A) DELTA(in A) NPOINTS] perfil.txt\n",argc); + printf("O bien: milos NLAMBDA MAX_ITER CLASSICAL_ESTIMATES RFS [DELTA(in A)] perfil.txt\n --> for using stored CRISP's PSF\n"); + printf("Note : CLASSICAL_ESTIMATES=> 0: Disabled, 1: Enabled, 2: Only Classical Estimates.\n"); + printf("RFS : 0: Disabled 1: Synthesis 2: Synthesis and Response Functions\n"); + printf("Note when RFS>0: perfil.txt is considered as models.txt. \n"); + + return -1; + } + + NLAMBDA = atoi(argv[1]); + + input_iter = argv[2]; + Max_iter = atoi(input_iter); + CLASSICAL_ESTIMATES = atoi(argv[3]); + RFS = atoi(argv[4]); + + if(CLASSICAL_ESTIMATES!=0 && CLASSICAL_ESTIMATES != 1 && CLASSICAL_ESTIMATES != 2){ + printf("milos: Error in CLASSICAL_ESTIMATES parameter. [0,1,2] are valid values. Not accepted: %d\n",CLASSICAL_ESTIMATES); + return -1; + } + + if(RFS != 0 && RFS != 1 && RFS != 2){ + printf("milos: Error in RFS parameter. [0,1,2] are valid values. Not accepted: %d\n",RFS); + return -1; + } + + if(argc ==6){ //if no filter declared + nombre = argv[5]; //input file name + } + else{ + INSTRUMENTAL_CONVOLUTION = 1; + if(argc ==7){ + INSTRUMENTAL_CONVOLUTION_WITH_PSF = 1; + DELTA = atof(argv[5]); + nombre = argv[6]; + FWHM = 0.035; + } + else{ + INSTRUMENTAL_CONVOLUTION_WITH_PSF = 0; + FWHM = atof(argv[5]); + DELTA = atof(argv[6]); + NMUESTRAS_G = atoi(argv[7]); + nombre = argv[8]; + } + } + + + nlambda=NLAMBDA; + //Generamos la gaussiana -> perfil instrumental + + + + if(INSTRUMENTAL_CONVOLUTION){ + G=vgauss(FWHM,NMUESTRAS_G,DELTA); + + + if(INSTRUMENTAL_CONVOLUTION_WITH_PSF){ + + free(G); + NMUESTRAS_G = 17; + + G=vgauss(FWHM,NMUESTRAS_G,DELTA); //solo para reservar memoria + + int kk; + PRECISION sum =0; + for(kk=0;kk 140) //140 length de crisp_psf + G[kk]=0; + else + G[kk] = crisp_psf[pos]; //70 es el centro de psf + + sum += G[kk]; + } + + for(kk=0;kk0.25?(lambda[nlambda-1] * 0.35):0.1); //David 0I.3 y Ic*0.7 + // initModel.S1 = (lambda[nlambda-1]>0.25?(lambda[nlambda-1] * 0.65):0.25); + + } + + //inversion + if(CLASSICAL_ESTIMATES!=2 || RFS) + lm_mils(cuantic,wlines,nwlines,lambda, nlambda,spectro,nlambda,&initModel,spectra,err,&chisqrf,&iter,slight,toplim,miter, + weight,nweight,fix,sig,filter,ilambda,noise,pol,getshi,0); + + + secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC; + //printf("\n\n%.16g milisegundos\n", secs * 1000.0); + + total_secs += secs; + + totalIter+=iter; + + //chisqrf_array[contador]=chisqrf; + + //[contador;iter;B;GM;AZI;etha0;lambdadopp;aa;vlos;S0;S1;final_chisqr]; + printf("%d\n",contador); + printf("%d\n",iter); + printf("%f\n",initModel.B); + printf("%f\n",initModel.gm); + printf("%f\n",initModel.az); + printf("%f \n",initModel.eta0); + printf("%f\n",initModel.dopp); + printf("%f\n",initModel.aa); + printf("%f\n",initModel.vlos); //km/s + //printf("alfa \t:%f\n",initModel.alfa); //stay light factor + printf("%f\n",initModel.S0); + printf("%f\n",initModel.S1); + printf("%.10e\n",chisqrf); + + /* + //For debugging: escribe tambien los perfiles + int kk; + for(kk=0;kkgms de initmodel + nfree=CalculaNfree(spectro,nspectro); + //printf("\n nfree! %d:\n",nfree); + //exit(-1); + + + if(nfree==0){ + return -1; //'NOT ENOUGH POINTS' + } + + flambda=ilambda; + + if(fix==NULL){ + fixed=calloc(NTERMS,sizeof(double)); + for(i=0;iB); + printf("%f\n",initModel->gm); + printf("%f\n",initModel->az); + printf("%f \n",initModel->eta0); + printf("%f\n",initModel->dopp); + printf("%f\n",initModel->aa); + printf("%f\n",initModel->vlos); //km/s + //printf("alfa \t:%f\n",initModel.alfa); //stay light factor + printf("%f\n",initModel->S0); + printf("%f\n",initModel->S1); + printf("%.10e\n",ochisqr); +*/ + + }while(iter<=miter); // && !clanda); + + *iterOut=iter; + + *chisqrf=ochisqr; + + + + if(fix==NULL) + free(fixed); + + + return 1; +} + +int CalculaNfree(PRECISION *spectro,int nspectro){ + int nfree,i,j; + nfree=0; + + /* + for(j=0;j<4*nspectro;j++){ + if(spectro[j]!=0.0){ + nfree++; + } + } + nfree=nfree-NTERMS;//NTERMS; + */ + + nfree = (nspectro*NPARMS) - NTERMS; + + + return nfree; +} + + +/* +* +* +* Cálculo de las estimaciones clásicas. +* +* +* lambda_0 : centro de la línea +* lambda : vector de muestras +* nlambda : numero de muesras +* spectro : vector [I,Q,U,V] +* initModel: Modelo de atmosfera a ser modificado +* +* +* +* @Author: Juan Pedro Cobos Carrascosa (IAA-CSIC) +* jpedro@iaa.es +* @Date: Nov. 2011 +* +*/ +void estimacionesClasicas(PRECISION lambda_0,double *lambda,int nlambda,PRECISION *spectro,Init_Model *initModel){ + + PRECISION x,y,aux,LM_lambda_plus,LM_lambda_minus,Blos,beta_B,Ic,Vlos; + PRECISION *spectroI,*spectroQ,*spectroU,*spectroV; + PRECISION L,m,gamma, gamma_rad,tan_gamma,maxV,minV,C,maxWh,minWh; + int i,j; + + spectroI=spectro; + spectroQ=spectro+nlambda; + spectroU=spectro+nlambda*2; + spectroV=spectro+nlambda*3; + + Ic= spectro[nlambda-1]; // Continuo ultimo valor de I + + + x=0; + y=0; + for(i=0;iGEFF); + beta_B = 1 / C; + + Blos = beta_B * ((LM_lambda_plus - LM_lambda_minus)/2); + Vlos = ( VLIGHT / lambda_0) * ((LM_lambda_plus + LM_lambda_minus)/2); + + + + Blos=Blos ; //factor de correción x campo debil + Vlos = Vlos ; //factor de correción ... + + //inclinacion + x = 0; + y = 0; + for(i=0;i 1e-5 ? x : 0; + y = fabs(y) > 1e- ? y : 0; + + tan_gamma = fabs(sqrtf(x/y)); + + tan_gamma = fabs(tan_gamma) > 1e-5 ? tan_gamma : 0; + + gamma_rad = atanf(tan_gamma); //gamma en radianes + + gamma_rad = fabs(gamma_rad) > 1e-5 ? gamma_rad : 0; + + gamma = gamma_rad * (180/ PI); //gamma en grados + + + //correccion + //utilizamos el signo de Blos para ver corregir el cuadrante + if (Blos<0) + gamma = 180-gamma; + + + + //azimuth + + PRECISION tan2phi,phi; + int muestra; + + if(nlambda==6) + muestra = CLASSICAL_ESTIMATES_SAMPLE_REF; + else + muestra = nlambda*0.5; + + + tan2phi=spectroU[muestra]/spectroQ[muestra]; + + // printf("tan2phi : %f \n",tan2phi); + // printf("%.10e \n",spectroU[muestra]); + // printf("%.10e \n",spectroQ[muestra]); + + + phi= (atan(tan2phi)*180/PI) / 2; //atan con paso a grados + + //printf("atan : %f \n",phi*2); + + // printf("%.10e \n",atan(tan2phi)); + + if(spectroU[muestra] > 0 && spectroQ[muestra] > 0 ) + phi=phi; + else + if (spectroU[muestra] < 0 && spectroQ[muestra] > 0 ) + phi=phi + 180; + else + if (spectroU[muestra] < 0 && spectroQ[muestra] < 0 ) + phi=phi + 90; + else + if (spectroU[muestra] > 0 && spectroQ[muestra]< 0 ) + phi=phi + 90; + + // printf("%.10e \n",phi); + + //printf("Blos : %f \n",Blos); + //printf("vlos : %f \n",Vlos); + //printf("gamma : %f \n",gamma); + //printf("phi : %f \n",phi); + + + PRECISION B_aux; + + B_aux = fabs(Blos/cos(gamma_rad))*1.5; + + //Vlos = Vlos * 1.5; + if(Vlos < (-5)) + Vlos= -5; + if(Vlos >(5)) + Vlos=(5); + + if(phi< 0) + phi = 180 + (phi); + if(phi > 180){ + phi = phi -180.0; + } + + // printf("%.10e \n",phi); + + initModel->B = (B_aux>4000?4000:B_aux); + initModel->vlos=Vlos;//(Vlos*1.5);//1.5; + initModel->gm=gamma; + initModel->az=phi; + initModel->S0= Blos; + +} + +void FijaACeroDerivadasNoNecesarias(PRECISION * d_spectra,int *fixed,int nlambda){ + + int In,j,i; + for(In=0;Ineta0=model->eta0-delta[0]; // 0 + } + if(fixed[1]){ + if(delta[1]< -800) //300 + delta[1]=-800; + else + if(delta[1] >800) + delta[1]=800; + modelout->B=model->B-delta[1];//magnetic field + } + if(fixed[2]){ + + if(delta[2]>2) + delta[2] = 2; + + if(delta[2]<-2) + delta[2] = -2; + + modelout->vlos=model->vlos-delta[2]; + } + + if(fixed[3]){ + + // if(delta[3]>1e-2) + // delta[3] = 1e-2; + // else + // if(delta[3]<-1e-2) + // delta[3] = -1e-2; + + modelout->dopp=model->dopp-delta[3]; + } + + if(fixed[4]) + modelout->aa=model->aa-delta[4]; + + if(fixed[5]){ + if(delta[5]< -30) //15 + delta[5]=-30; + else + if(delta[5] > 30) + delta[5]=30; + + modelout->gm=model->gm-delta[5]; //5 + } + if(fixed[6]){ + if(delta[6]< -30) + delta[6]=-30; + else + if(delta[6] > 30) + delta[6]= 30; + + modelout->az=model->az-delta[6]; + } + if(fixed[7]) + modelout->S0=model->S0-delta[7]; + if(fixed[8]) + modelout->S1=model->S1-delta[8]; + if(fixed[9]) + modelout->mac=model->mac-delta[9]; //9 + if(fixed[10]) + modelout->alfa=model->alfa-delta[10]; +} + +/* + Tamaño de H es NTERMS x NTERMS + Tamaño de beta es 1xNTERMS + + return en delta tam 1xNTERMS +*/ + +int mil_svd(PRECISION *h,PRECISION *beta,PRECISION *delta){ + + double epsilon,top; + static PRECISION v2[TAMANIO_SVD][TAMANIO_SVD],w2[TAMANIO_SVD],v[NTERMS*NTERMS],w[NTERMS]; + static PRECISION h1[NTERMS*NTERMS],h_svd[TAMANIO_SVD*TAMANIO_SVD]; + static PRECISION aux[NTERMS*NTERMS]; + int i,j; +// static double aux2[NTERMS*NTERMS]; + static PRECISION aux2[NTERMS]; + int aux_nf,aux_nc; + PRECISION factor,maximo,minimo; + int posi,posj; + + epsilon= 1e-12; + top=1.0; + + factor=0; + maximo=0; + minimo=1000000000; + + + /**/ + for(j=0;jmaximo){ + maximo=fabs(h[j]); + } + } + + factor=maximo; + + //printf("maximo : %.12e \n",maximo); + //exit(-1); + + + if(!NORMALIZATION_SVD) + factor = 1; + + for(j=0;j epsilon) ? (1/waux[i]): (1/epsilon));//((waux[i]>0)?(1/epsilon):(-1/epsilon))); //(1/waux[i]) : 0);// + } + + multmatrix(vaux,NTERMS,NTERMS,aux2,NTERMS,1,delta,&aux_nf,&aux_nc); + +/* + printf("\n"); + printf("#################################### delta \n"); + int j1; + for(j1=0;j1gm < 0) + model->gm = -(model->gm); + if(model->gm > 180) + model->gm =180-(((int)floor(model->gm) % 180)+(model->gm-floor(model->gm)));//180-((int)model->gm % 180);*/ + + //Magnetic field + if(model->B < 0){ + //model->B = 190; + model->B = -(model->B); + // model->gm = 180.0 -(model->gm); + } + if(model->B > 5000) + model->B= 5000; + + //Inclination + if(model->gm < 0) + model->gm = -(model->gm); + if(model->gm > 180){ + model->gm = 360.0 - model->gm; + // model->gm = 179; //360.0 - model->gm; + } + + //azimuth + if(model->az < 0) + model->az= 180 + (model->az); //model->az= 180 + (model->az); + if(model->az > 180){ + model->az =model->az -180.0; + // model->az = 179.0; + } + + //RANGOS + //Eta0 + if(model->eta0 < 1) + model->eta0=1; + + // if(model->eta0 >8) + // model->eta0=8; + if(model->eta0 >2500) //idl 2500 + model->eta0=2500; + + //velocity + if(model->vlos < (-20)) //20 + model->vlos= (-20); + if(model->vlos >20) + model->vlos=20; + + //doppler width ;Do NOT CHANGE THIS + if(model->dopp < 0.0001) + model->dopp = 0.0001; + + if(model->dopp > 0.6) // idl 0.6 + model->dopp = 0.6; + + + if(model->aa < 0.0001) // idl 1e-4 + model->aa = 0.0001; + if(model->aa > 10) //10 + model->aa = 10; + + //S0 + if(model->S0 < 0.0001) + model->S0 = 0.0001; + if(model->S0 > 1.500) + model->S0 = 1.500; + + //S1 + if(model->S1 < 0.0001) + model->S1 = 0.0001; + if(model->S1 > 2.000) + model->S1 = 2.000; + + //macroturbulence + if(model->mac < 0) + model->mac = 0; + if(model->mac > 4) + model->mac = 4; + + //filling factor +/* if(model->S1 < 0) + model->S1 = 0; + if(model->S1 > 1) + model->S1 = 1;*/ + + return 1; +} + + + + + +void spectral_synthesis_convolution(){ + + int i; + int nlambda=NLAMBDA; + + //convolucionamos los perfiles IQUV (spectra) + if(INSTRUMENTAL_CONVOLUTION){ + + PRECISION Ic; + + + + if(!INSTRUMENTAL_CONVOLUTION_INTERPOLACION){ + //convolucion de I + Ic=spectra[nlambda-1]; + + for(i=0;i + +clock_t t_ini, t_fin; +double secs, total_secs; + +t_ini = clock(); + +call FUNCTION to TEST! + +t_fin = clock(); + +secs = (double)(t_fin - t_ini) / CLOCKS_PER_SEC; +printf("\n\n%.16g milisegundos\n", secs * 1000.0); \ No newline at end of file diff --git a/cmilos/defines.h b/cmilos/defines.h index c9a5abb..c9ea1a5 100755 --- a/cmilos/defines.h +++ b/cmilos/defines.h @@ -44,6 +44,21 @@ // #define INITIAL_MODEL_S0 0.35 // #define INITIAL_MODEL_S1 0.85 +// RTE init model config ONBOARD +// Inv Iterations = 15 +// Initial Model Continuum Absoprtion = 12.0000 // INITIAL_MODEL_ETHA0 +// Initial Model Vector Magnetic Field Strength = 1200.00000 // INITIAL_MODEL_B +// Initial Model Line-Of-Sight Velocity = 0.05000 // INITIAL_MODEL_VLOS +// Initial Model Doppler Width Of Line = 0.05000 // INITIAL_MODEL_LAMBDADOPP +// Initial Model Damping Parameter = 0.05000 // INITIAL_MODEL_AA +// Initial Model Vector Magnetic Field Inclination = 170.00000 // INITIAL_MODEL_GM +// Initial Model Vector Magnetic Field Azimuth = 25.00000 // INITIAL_MODEL_AZI +// Initial Model Source Function Ordinate At Origin = 0.30000 // INITIAL_MODEL_S0 +// Initial Model Source Function Slope = 0.80000 // INITIAL_MODEL_S1 +// Wavelength Setting Initial Sampling Wavelength = 6173.20117 +// Wavelength Setting Spectral Line Step = 0.07000 +// Wavelength Setting Wavelength Of Line Continuum = 6173.04117 (blue) 6173.64117 (red) + #define INITIAL_MODEL_B 400 #define INITIAL_MODEL_GM 30 #define INITIAL_MODEL_AZI 120 @@ -54,7 +69,6 @@ #define INITIAL_MODEL_S0 0.15 #define INITIAL_MODEL_S1 0.85 - //NumeroS cuanticos #define CUANTIC_NWL 1 #define CUANTIC_SLOI 2 diff --git a/cmilos/milos b/cmilos/milos index 689942e938c9bba93c356050761be8a9c112e56d..7c45baad52d7649986c524584258b9ee66fb0b82 100755 GIT binary patch delta 2586 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 PU)Ad)-5J?|TYdfyCNZ5w diff --git a/cmilos/milos.o b/cmilos/milos.o index 67b1d878d99ee0315ff4b3458dfb2d3eaf800913..0a08cb9616b47273261f1060b5d6b62188366872 100644 GIT binary patch delta 4093 zcmZ9P3s6+o8OQfPG&Z?+s+n<)cN!+8Y9wu##ff<|bp9~lkp!6REoUDq78VVC|#bDG#jS8fa1S|5;4Jaa-aSgPScTD@8?_Orl<;?KA z=YIeH`Ob6CF1=S0o312oO%Z9$5442DVhn^9BBeMjl3P6G`_rm~$5rk}d4*Rzh!Yi3 zJcKdg#g2!`@M|g5mZ2L^7T_%#ZNlL1mPhknw^SJ&y6j6OC*ZrJft&?HYYiIa? z-c?s->8MxmD7dlW5P>^BdbS#~J5CSV7L8vGYlklXI!# z{NXdU^AX4S3{H@`j?`(MJ3MK&NHx2ZV~p~gLNoPPjbvgi*Xyu^>Wy4KpnAdj>KWoB zzn|q^|IO@YUct2OQjBo@78Y)oRswaP`Wr9fwaHjZ&J=VJy{IAQJja>gSf@D8$Jz4> z=AU?70?fZ~WIb~uvy9oqYAf?3N6s<(m|rvRL-OlV+)wmc^CqbgPV!{X%Bb>!GsFeT zV?9BtI$;^BZFQIZ@T^2LW%xbwCFU!b7M5ZQa|g4Ld5n3I*~UD}>}Gz<97FjIDZXRg z4MFu0j^A`tmHBh7f1`-4J4VHPb}wYo&QqHu%;mVeGY5k^XP}+_GIq@nf97}*YIfy_ z?Ofl23rt~><~=$_I8QmjVZfdV>BNs)cT(~$z&lqvF&cPPhNqh;{<;{C2c^pJF^r(LS~mRnuEAl~*x z_(*+G%lwH;^-oYk>3ZAn1a(%1u69mP-*c(AC#Xvo#@nt&YOA#JDKNfbI~T>(JY=^@ zQGh^ej?2^VWZaXFSnC%0v;+@JG#oa}^UkfTRy-e#hqq9B-`hE&5aGAgJ}o+uL##XE zrQPa2vW4P#M+-y{(WBA|YU4P*B;H3}#5`6h#B-6lcjhFBqDbfQoK}ak=UsL zAwuXpBXRbOVHW*1-fkmqpOIFHmNj>IT-}7!Hm`UY*=^F?sCgFQa+^d|n}N;r*VH!4 zdRbHb+3^e;5hLf#HbcCDBC4gd&!T);?b6cor92yN@plB}sE7m1=ogHP;42 z+r6R;W`~5)VVDUy@eCpOC_0~_FKN*-_&eM)U9YK|5bjVj?d*`0b+{u_Y>lM8|Ai3c zn0@wL*D$J9#=F{p+h?UHk4*1OPY~;|>_e}3H4^%e+La;LMbqdq%xmhNprW=rghq-s zQ1n;NbC9EDh<3S$_OzyMf_Y92&38@>ZP__BwD7qv1RBm$@)zQ1=q#O=R)_-QC-o`k z+eLLN_HDa>vr#EvUb`7@RRFit6>)WI^J&p;qEO0NWDN)>oLrq zI=_}wuR!(%X+rCDC6dWkb-{2&{Tyw-KqrcnN-aYOu?y1LMj5_z?%G3|T8X3{iF>Kn z4p%g*M_Scdua`9y2$HIw`TuAtZ4qTu^O&wCKt(;aBibX)LaL3g?M!r$Z$|HY7`=v> zrFp~f_e#1aL%r@h;k@R_$L(G(*7O>9tk1xMeTF&N`JJFl`N-~**i6xTwdhWi_DNBL zx<0SMH7B!*( z8mVPKYgwbIg@{g2n=~~5^P;r&YHi=q)P3-gx=B;t*Hk)j7ro*&gfI5cJs7xDAm~Q9 zB*ot_De4vb@h~%wS;0Kb{ERvKW93=K3^7}n!_4UeUTeSBZ~dM0LPgED0@(x7dV^}? z`#r3wub^~-`lY7U#)FVcorCNpsQ|N_?%3qJ9LFLIJzJ}nSwA7_M-dDBeT#m*; zI*)^f*{?;PMUJ#+XS%O3fOg8}zDS zX5OVnY>&ARLDEXmI3&#t6dNCH8EVLVeaN64`fSLHOGAbk)!G%qch!9_J#jZDbuK^u zRf%t@ufLz57s()%mG_@K*QuWMVYibD^NnNM)dzTp> za|xo?X#cMn<|A5k1YDxYHAF29H+Mu+Vs zB^oe1;w4VMuGW1Ku>k>Q9kZJ`=>~r?nc;33DZG)NC^8~rH{TWX9oc*ei$5 zfAri>(?t{35)Y!8*oiUXN0>XBE`E-+qv_Kh+icG{cZU7EhaS)2^yp8%SGC8E?8aB4 MkBUEH?%16F0~vYCVgLXD delta 4268 zcmZ9Qe^6D&6~|f77TSB0kcnCERGQe)XePc~bj+k?Lcul`&Bz3kCZkgjOh+XYQf&so z#AhWc1T+D1L7to|hN+?y?o?Q7x2e#X?JcOYTwutbns~ zl;;8Mctv_fEU{c3lhrno+Ah`TUt4O}6l?AwbwH}QuUl5{?ff@f!CfL@w1~4n7%kw& zV|Wg6_o7!=o+Z}gXM>shxUop8p}(=rtK}|>DR#M3b5~mGb{V@0(lItps`0?3{;R~(#8fl*{Iafs~ylB&o&F4nN^ zixCz^-oGS9!u(so_ABCA^4U(@ zMFe62alasJE1Av?(RHaay@dO-P$)d|Gyg@Q&ND~0Plbr%r`S5@*zrt%wjS(XM;hz# zT^awcH5z|ny*T1ySr46Gb078OPgPZ~;Fw`{MJm!k>#B-4AOAPzsQ$J}-)zswPHF8G zTRDt*qE7nyxMZ&sK8avInaYx2?BrKShcnf9AFbZX2VZ=&*B`)kinI4&$*E?R2q9IG zMxx^RPQPpt})1*OlwMO&p>K(?1iuY5p(~Df2Ao(nZq_Z02p54LHVA{DjW`~q>;;Dt4 zk3-teoA`9f&*z{$>_V!sRmt?6{7WD*Z3XuQ&el2mFBCAg)@i>u$De)dEWO+uz&-~1 zReV^^YgauCE?n32KgvEY;xeJ;IyXL1vaX833mihtf}!i2Wy923Q%}Wf?}@iS_jL{{ zYc<$XtLZCbcNY=aV6Qb)ME`ySU1Ru}N7jK|N|qT^c00G-iW57l$<0 zEcO{VT%7HMDwhf4E=?a_jfruH{JAiJUi0cSJt&ThWX%Ly9XE2&;H_}8qGmyCoj65G zooT42IIsBRKuujF%X3b>@jYXo!^Gb%VHq_yxv^78TKn#!EkAb--3<3<>0rBM!n|9W zGvU^^43g?Ky-U0sIIMD$>p2`i>yTp21V_DZxhq6xkuh1|t{3I@*ZY>cTk**OTZ1S! zr2)&ux2O@{qDD=Re(zD53~)4ZBNGkYdvZ`wbHI%;;}~;7v1Y?Wqj-9@CT?s}B43lg zUBr<#L2MJpJ;UyC*xi(7>{0v{%3nUhFB3xUa36JrqV9pHI~EnTcnFl=naFRWFA<>>o5{>~9Ygd75UtI4)Qc`G;e;#GaeL(Z&tCvfB|K)s3q9zMN6iuV4bz zqe|>GMa>3VyLg+Hw43-#C#Ag^`&?84Xb6`yuc0P}W+L*^g&h9dee8nS6{^S(rih*SGKG3DZowtQ6k;i{i8!@Ks4o%M67z}Ih+{pbQL0oF@guyzAu9R=!g@JAjkkME z{WHAwo;?$0_Hj7ctHF4$rteoG@SEs08FuJi4zHrtt7sWu>+@}S%jCZW#9r8;`=~?r z`L?_a#RvaV;l43_8g%u|GRl;S`hC1Y`mOKcKeAUuXy}SV?2`jg{o=i`qmSAdPbfZF zP>yO5dV5cNQBez_6V=U%TBoQ5pbu~(TTwlViairmHS>3hS_sLgW?`)Nn+?$M0*9!4 zGdKqDO&HMhV8xmZZnVY>YWix$S_BiA={Ut&IIO4zU>n5FjWMSb>+c|Tkn3t~E*Qn! z`vzyRa;OR z5HuXlF2ge9Rmd6+_wUSrnTbzB*YI4{1wkX>_&*HGM#85p-E9?~Hr<+^#Az)!MqUWI XTw+;{LjB0gLHq7oSLYyj=$ZckOAYhZ diff --git a/src/__pycache__/hrt_pipe.cpython-38.pyc b/src/__pycache__/hrt_pipe.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e24829f8e4c11a3a6ad075eebcf3378a3984a14 GIT binary patch literal 17938 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 Vn+fiUjSMUV=Yv15ycNIH{{^PCucH6} literal 0 HcmV?d00001 diff --git a/src/__pycache__/utils.cpython-38.pyc b/src/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7365465bff033080488c00ba841060b2ccf973fa GIT binary patch literal 12666 zcmb7KTWlQHd7hb_ot<4Smy|@^ZDr&*kv5?y$(K}S6j?Gw*=l5pCMjE9Ti6Wu49O+; zrZYo{+{~s(C?{@F$LS?$6330$q(z0IK#&$if%c*3Ls1kBP@pfx00n{sMXRC@1qu|X z9^!uAnZ1xpS#_73nKS1$=luWoU(SEdwZXxRhTpLpUw8MN(X^lQW$Q12m-D#%zsF5z zLa%65y`bw%8x^CFP*1a9s%Nrl6;itPq9zi;yrT(o!zkFEy_^=w@9Dx4sXIm?BW#hr zqZJ0kr^SHC-q8zLF)DIm2&q9aEOwzRCw7ZHcn*mXu@}!_u}|#BbC)Qp`(*~Mbbt$M{` zlqnXgb+KAuI$JE>Ty-n$66>YO3l}G63f9%nzi{Q+WR$x4`4?vFD} znU^kHzEUtJr!Gzu%ona+xmZYFn?jQ-m!~G9=8x|vd~hEO1qHuZQL|tx1P~Qbh!`d66ezSaX!2zaJA=jSIuctZ|Q-t zoCtNHAJmpjq?5vU$7mVt9IKTGjWDr5kS3b{mT{a)-4#x-Zy0905UMf;LVA~^MhhjnvxHE65`-7b(I1je1(YPGTMxKg_7qihPo zu6VvvuDXkS)STn8etXmbKS!P0w?>^ty^`m!mONK@a@<)0WZN%JeSX<11*6^9odc1i z9{7_K!Ft2Xr=)@R$gDTKT4dB3QOfnzP$H9~E2I`cmEh^8A}jt}-i%Dnx?uCO#h}`d zhtYw2jJGblV=ksi&?1R>0HrY_b6I1bkul^EAc&!XmoEg#1!q z-c5$urY=%Ig(d8RS}TP%DUn8RDUms-9oC-XH_R}(V7#Wy0$xFCB_n^NYy3mM1EGdK zZSQrbt5+`1H9v8&e5)(~FlT<9Sef@EQR0?LtJT$t0-QhY$Q-)6pT;d3 zo_^_a@$$sj9Xju6wB{_fM4_DlQT0{XGWcCHFv(^IYHea<9mP~cfQz~%4ZaN zl(5BuOTH+eNODqfJW5ZlmAnS=E@|7M%&Tr?)ti*EF7vj0oLMO!S`8yF?3ynJ#ZtX? z%Y#~DrdPo;6I}HcaDyVH+cOj^Hn2 zp$`F1lnmiNQ!dNlnn?W+nh~znxZ$sbI`5s!E`T+&b6;qz+m4>M>c^2>t(KjHT6q#SrTFIMdUelh{UeRW>>x3@F zK>_%H)*3(xb#cd6@t#$^5469M-PBjiZ|Ks%>;`M5NVNt-9q;>s6u>>WK~YJCHpD8u zUu)&U9N)sh1*-pS^Jfaax7}M_(OoP1qqpjnfU4>uSUDQ3)@tB5ne7K|Ef_5|>b~##wHLtpwsynkMC!AXz6lghsZK+EME#`@%M~|us?LJO9Zsd%-;V99Z70^fV~VRfn7VU{wg(@T`b+36Rj*DK|D-+|D~)$0|i zc*nUJ9LAz)Nk>dpJfPcGa~cHXq}@1DO;l-;LxZ9X>99VBL7RyF}cCk;MFlEZl4r(2L%3$?O_97oG-7M;2#g^Mike}tRR zg>eU#;3C8XHeK7$epUOLwxGlLHSXAy*6NQDXX8bFZJVUpHlKRqN1 z!k83EC4|9E_Lo6Bij58t8ECG?uwC*>E3n|P5$>1*=)IcnECCD3Nq{_f&c(|YofCKk zq;J<(E5a$ctG)*)1LXcH9Fn?p;EK`+5W{ulNjSoTyQ=(@7`5BTNQ@D?vn1muaa#ll zZyX^3K@fP^FoAH4==i+_&9R~XhH;bfZ8no*WU@kk`M+T_rt(IV0Lr4I56KPiW{jPR zOwOYp9+|VmW2s(koZH}cDK3^~Xw8qqw=J!}7l4pr!v5GObTt@yo~{siLw*j8B7N;1Rvy0RwTDXYQa+E{ zS8*wigu}D7jMh9d2g)ku93wxVTqHP9sW_{(^37FGj-f>}%}OX8cbbD#K+4ALbC2HNeGq z6`#Cm2nfSHeTvSnzvROCZG$8Q(}DhjdwO9&nUkU_j%lgZBk8k?Ud>x;$a6p72S^5! zuzoxyuU~F@TM*r;+dOsw@S(txdB^>HpVW6})qJ*#y|{`fFD!TxLvp%x{G;&sCu_

wO(u`d$dLbbjGX|~uu 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 diff --git a/hrt_pipe.py b/hrt_pipe.py deleted file mode 100644 index e5d7a7b..0000000 --- a/hrt_pipe.py +++ /dev/null @@ -1,817 +0,0 @@ -from posix import listdir -import numpy as np -import os.path -from astropy.io import fits -# from scipy.ndimage import gaussian_filter -import time -import datetime -from operator import itemgetter -import json -import matplotlib.pyplot as plt -from numpy.core.numeric import True_ - -from utils import * -from hrt_pipe_sub import * - - -def phihrt_pipe(input_json_file): - - ''' - PHI-HRT data reduction pipeline - 1. read in science data (+ OPTION: scaling) open path option + open for several scans at once - 2. read in flat field (+scaling)- just accepts one flat field fits file - 3. read in dark field (+scaling) - 4. apply dark field - 5. option to clean flat field with unsharp masking - 6. normalise flat field - 7. apply flat field - 8. apply prefilter - 9. read in field stop - 10. apply field stop - 11. demodulate with const demod matrix - a) option to output demod to fits file - 12. normalise to quiet sun - 13. calibration - a) ghost correction - not implemented yet - b) cross talk correction - 14. rte inversion with pmilos/cmilos (CE, RTE or CE+RTE) - a) output rte data products to fits file - - Parameters - ---------- - Input: - data_f : list or string - list containing paths to fits files of the raw HRT data OR string of path to one file - must have last 10 characters before .fits as the DID - for naming purposes of output files - dark_f : string, DEFAULT '' - Fits file of a dark file (ONLY ONE FILE) - flat_f : string, DEFAULT '' - Fits file of a HRT flatfield (ONLY ONE FILE) - - ** Options: - L1_input: bool, DEFAULT True - ovverides scale_data, bit_conversion, and accum_scaling, so that correct scaling for L1 data applied - L1_8_generate: bool, DEFAULT False - if True, assumes L1 input, and generates RTE output with the calibration header information - scale_data: bool, DEFAULT True - performs the accumulation scaling + conversion for flat and science (only FALSE for commissioning data) - bit_conversion: bool, DEFAULT True - divides the scan + flat by 256 to convert from 24.8bit to 32bits - norm_f: bool, DEFAULT: True - to normalise the flat fields before applying - clean_f: str, DEFAULT: None - clean the flat field with unsharp masking, accepted values = ['blurring','fft'] - sigma: int, DEFAULT: 59 - sigma of the gaussian convolution used for unsharp masking if clean_f == 'blurring', 'fft' - clean_mode: str, DEFAULT: "V" - The polarisation states of the flat field to be unsharp masked, options are "V", "UV" and "QUV" - flat_states: int, DEFAULT: 24 - Number of flat fields to be applied, options are 4 (one for each pol state), 6 (one for each wavelength), 24 (one for each image) - prefilter_f: str, DEFAULT None - file path location to prefilter fits file, apply prefilter correction - flat_c: bool, DEFAULT: True - apply flat field correction - dark_c: bool, DEFAULT: True - apply dark field correction - fs_c: bool, DEFAULT True - apply HRT field stop - limb: str, DEFAULT None - specify if it is a limb observation, options are 'N', 'S', 'W', 'E' - demod: bool, DEFAULT: True - apply demodulate to the stokes - norm_stokes: bool, DEFAULT: True - normalise the stokes vector to the quiet sun (I_continuum) - out_dir : string, DEFUALT: './' - directory for the output files - out_stokes_file: bool, DEFAULT: False - output file with the stokes vectors to fits file - out_stokes_filename: str, DEFAULT = None - if None, takes last 10 characters of input scan filename (assumes its a DID), change if want other name - ItoQUV: bool, DEFAULT: False - apply I -> Q,U,V correction - ctalk_params: numpy arr, DEFAULT: None - cross talk parameters for ItoQUV, (2,3) numpy array required: first axis: Slope, Offset (Normalised to I_c) - second axis: Q,U,V - rte: str, DEFAULT: False - invert using cmilos, options: 'RTE' for Milne Eddington Inversion, 'CE' for Classical Estimates, 'CE+RTE' for combined - out_rte_filename: str, DEFAULT = '' - if '', takes last 10 characters of input scan filename (assumes its a DID), change if want other name - p_milos: bool, DEFAULT = True - if True, will execute the RTE inversion using the parallel version of the CMILOS code on 16 processors - Returns - ------- - data: numpy array - stokes vector - flat: numpy array - flat field - - References - ---------- - SPGYlib - - ''' - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc('PHI HRT data reduction software ',bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - #----------------- - # READ INPUT JSON - #----------------- - - input_dict = json.load(open(input_json_file)) - - try: - data_f = input_dict['data_f'] - flat_f = input_dict['flat_f'] - dark_f = input_dict['dark_f'] - - L1_input = input_dict['L1_input'] - L1_8_generate = input_dict['L1_8_generate'] - scale_data = input_dict['scale_data'] - accum_scaling = input_dict['accum_scaling'] - bit_conversion = input_dict['bit_conversion'] - - dark_c = input_dict['dark_c'] - flat_c = input_dict['flat_c'] - norm_f = input_dict['norm_f'] - clean_f = input_dict['clean_f'] - sigma = input_dict['sigma'] - clean_mode = input_dict['clean_mode'] - flat_states = input_dict['flat_states'] - prefilter_f = input_dict['prefilter_f'] - fs_c = input_dict['fs_c'] - limb = input_dict['limb'] - demod = input_dict['demod'] - norm_stokes = input_dict['norm_stokes'] - ItoQUV = input_dict['ItoQUV'] -# ctalk_params = input_dict['ctalk_params'] - rte = input_dict['rte'] - p_milos = input_dict['p_milos'] - cmilos_fits_opt = input_dict['cmilos_fits_opt'] - - out_dir = input_dict['out_dir'] - out_stokes_file = input_dict['out_stokes_file'] - out_stokes_filename = input_dict['out_stokes_filename'] - out_rte_filename = input_dict['out_rte_filename'] - - if 'config' not in input_dict: - config = True - else: - config = input_dict['config'] - - except Exception as e: - print(f"Missing key(s) in the input config file: {e}") - raise KeyError - - overall_time = time.time() - - if L1_input: - print("L1_input param set to True - Assuming L1 science data") - accum_scaling = True - bit_conversion = True - scale_data = True - - #----------------- - # READ DATA - #----------------- - - print(" ") - printc('-->>>>>>> Reading Data',color=bcolors.OKGREEN) - - start_time = time.time() - - if isinstance(data_f, str): - data_f = [data_f] - - if isinstance(data_f, list): - #if the data_f contains several scans - printc(f'Input contains {len(data_f)} scan(s)',color=bcolors.OKGREEN) - - number_of_scans = len(data_f) - - data_arr = [0]*number_of_scans - hdr_arr = [0]*number_of_scans - - wve_axis_arr = [0]*number_of_scans - cpos_arr = [0]*number_of_scans - voltagesData_arr = [0]*number_of_scans - tuning_constant_arr = [0]*number_of_scans - - for scan in range(number_of_scans): - data_arr[scan], hdr_arr[scan] = get_data(data_f[scan], scaling = accum_scaling, bit_convert_scale = bit_conversion, scale_data = scale_data) - - wve_axis_arr[scan], voltagesData_arr[scan], tuning_constant_arr[scan], cpos_arr[scan] = fits_get_sampling(data_f[scan],verbose = True) - - if 'IMGDIRX' in hdr_arr[scan] and hdr_arr[scan]['IMGDIRX'] == 'YES': - print(f"This scan has been flipped in the Y axis to conform to orientation standards. \n File: {data_f[scan]}") - - #-------- - # test if the scans have different sizes - #-------- - - check_size(data_arr) - - #-------- - # test if the scans have different continuum wavelength_positions - #-------- - - check_cpos(cpos_arr) - - #-------- - # test if the scans have different pmp temperatures - #-------- - - pmp_temp = check_pmp_temp(hdr_arr) - - #so that data is [y,x,24,scans] - data = np.stack(data_arr, axis = -1) - data = np.moveaxis(data, 0,-2) - - print(f"Data shape is {data.shape}") - - #-------- - # test if the scans have same IMGDIRX keyword - #-------- - - header_imgdirx_exists, imgdirx_flipped = check_IMGDIRX(hdr_arr) - - else: - printc("ERROR, data_f argument is neither a string nor list containing strings: {} \n Ending Process",data_f,color=bcolors.FAIL) - exit() - - data_shape = data.shape - - data_size = data_shape[:2] - - #converting to [y,x,pol,wv,scans] - - data = stokes_reshape(data) - - #enabling cropped datasets, so that the correct regions of the dark field and flat field are applied - print("Data reshaped to: ", data.shape) - - diff = 2048-data_size[0] #handling 0/2 errors - - if np.abs(diff) > 0: - - start_row = int((2048-data_size[0])/2) - start_col = int((2048-data_size[1])/2) - - else: - start_row, start_col = 0, 0 - - rows = slice(start_row,start_row + data_size[0]) - cols = slice(start_col,start_col + data_size[1]) - ceny = slice(data_size[0]//2 - data_size[0]//4, data_size[0]//2 + data_size[0]//4) - cenx = slice(data_size[1]//2 - data_size[1]//4, data_size[1]//2 + data_size[1]//4) - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load science data time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - - #----------------- - # READ FLAT FIELDS - #----------------- - - if flat_c: - print(" ") - printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) - - start_time = time.time() - - # flat from IP-5 - if '0024151020000' in flat_f or '0024150020000' in flat_f: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=False) - else: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=scale_data) - - if 'IMGDIRX' in header_flat: - header_fltdirx_exists = True - fltdirx_flipped = str(header_flat['IMGDIRX']) - else: - header_fltdirx_exists = False - fltdirx_flipped = 'NO' - - print(f"Flat field shape is {flat.shape}") - # correction based on science data - see if flat and science are both flipped or not - flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) - - flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] - flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states - flat = np.moveaxis(flat, 2,-1) - - print(flat.shape) - - _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position - - print(f"The continuum position of the flat field is at {cpos_f} index position") - - #-------- - # test if the science and flat have continuum at same position - #-------- - - flat = compare_cpos(flat,cpos_f,cpos_arr[0]) - - flat_pmp_temp = str(header_flat['HPMPTSP1']) - - print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") - - - #-------- - # correct for missing line in particular flat field - #-------- - - if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' - print("This flat has a missing line - filling in with neighbouring pixels") - flat_copy = flat.copy() - flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) - -# flat[1345, 296:, 1, 1] = flat_copy[1344, 296:, 1, 1] -# flat[1346, :291, 1, 1] = flat_copy[1345, :291, 1, 1] - del flat_copy - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - - else: - print(" ") - printc('-->>>>>>> No flats mode',color=bcolors.WARNING) - - - #----------------- - # READ AND CORRECT DARK FIELD - #----------------- - - if dark_c: - print(" ") - printc('-->>>>>>> Reading Darks ',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - - if dark_f[-19:] != '0022210004_000.fits': - dark,h = get_data(dark_f,scaling = accum_scaling, bit_convert_scale = bit_conversion,scale_data = scale_data) - else: - dark,h = get_data(dark_f, scaling = accum_scaling, bit_convert_scale = bit_conversion, scale_data = False) - - dark_shape = dark.shape - if dark_shape != (2048,2048): - - printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) - printc("Attempting to correct ",color=bcolors.WARNING) - - try: - if dark_shape[0] > 2048: - dark = dark[dark_shape[0]-2048:,:] - - except Exception: - printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) - # DC change 20211018 - if 'IMGDIRX' in h: - header_drkdirx_exists = True - drkdirx_flipped = str(h['IMGDIRX']) - else: - header_drkdirx_exists = False - drkdirx_flipped = 'NO' - - dark = compare_IMGDIRX(dark[np.newaxis],header_imgdirx_exists,imgdirx_flipped,header_drkdirx_exists,drkdirx_flipped)[0] - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - except Exception: - printc("ERROR, Unable to open darks file: {}",dark_f,color=bcolors.FAIL) - raise ValueError() - - #----------------- - # APPLY DARK CORRECTION - #----------------- - - if flat_c == False: - flat = np.empty((2048,2048,4,6)) - - data, flat = apply_dark_correction(data, flat, dark, rows, cols) - - if flat_c == False: - flat = np.empty((2048,2048,4,6)) - - # if out_intermediate: - # data_darkc = data.copy() - - else: - print(" ") - printc('-->>>>>>> No dark mode',color=bcolors.WARNING) - - - #----------------- - # OPTIONAL Unsharp Masking clean the flat field stokes Q, U or V images - #----------------- - - if clean_f is not None and flat_c: - print(" ") - printc('-->>>>>>> Cleaning flats with Unsharp Masking',color=bcolors.OKGREEN) - - start_time = time.time() - - flat = unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode, clean_f = "blurring") - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Cleaning flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - else: - print(" ") - printc('-->>>>>>> No clean flats mode',color=bcolors.WARNING) - - - #----------------- - # NORM FLAT FIELDS - #----------------- - - if norm_f and flat_c: - - flat = normalise_flat(flat, flat_f, ceny, cenx) - - else: - print(" ") - printc('-->>>>>>> No normalising flats mode',color=bcolors.WARNING) - - - #----------------- - # APPLY FLAT CORRECTION - #----------------- - - if flat_c: - try: - data = flat_correction(data,flat,flat_states,rows,cols) - - # if out_intermediate: - # data_flatc = data.copy() - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - except: - printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) - - else: - print(" ") - printc('-->>>>>>> No flat field correction mode',color=bcolors.WARNING) - - - #----------------- - # PREFILTER CORRECTION - #----------------- - - if prefilter_f is not None: - print(" ") - printc('-->>>>>>> Prefilter Correction',color=bcolors.OKGREEN) - - start_time = time.time() - - prefilter_voltages = [-1300.00,-1234.53,-1169.06,-1103.59,-1038.12,-972.644,-907.173,-841.702,-776.231,-710.760,-645.289, - -579.818,-514.347,-448.876,-383.404,-317.933,-252.462,-186.991,-121.520,-56.0490,9.42212,74.8932, - 140.364,205.835,271.307, 336.778,402.249,467.720,533.191,598.662,664.133,729.604,795.075,860.547, - 926.018,991.489,1056.96,1122.43,1187.90,1253.37, 1318.84,1384.32,1449.79,1515.26,1580.73,1646.20, - 1711.67,1777.14,1842.61] - - prefilter, _ = load_fits(prefilter_f) - - #prefilter = prefilter[:,652:1419,613:1380] #crop the helioseismology data - - data = prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages) - - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Prefilter correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - else: - print(" ") - printc('-->>>>>>> No prefilter mode',color=bcolors.WARNING) - - - #----------------- - # FIELD STOP - #----------------- - - if fs_c: - data, field_stop = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - - - else: - print(" ") - printc('-->>>>>>> No field stop mode',color=bcolors.WARNING) - - - #----------------- - # APPLY DEMODULATION - #----------------- - - if demod: - - print(" ") - printc('-->>>>>>> Demodulating data',color=bcolors.OKGREEN) - - start_time = time.time() - - data,_ = demod_hrt(data, pmp_temp) - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Demodulation time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - else: - print(" ") - printc('-->>>>>>> No demod mode',color=bcolors.WARNING) - - - #----------------- - # APPLY NORMALIZATION - #----------------- - - if norm_stokes: - - print(" ") - printc('-->>>>>>> Normalising Stokes to Quiet Sun',color=bcolors.OKGREEN) - - start_time = time.time() - - Ic_mask = np.zeros((data_size[0],data_size[1],data_shape[-1]),dtype=bool) - I_c = np.ones(data_shape[-1]) - if limb is not None: - limb_mask = np.zeros((data_size[0],data_size[1],data_shape[-1])) - - for scan in range(data_shape[-1]): - - #I_c = np.mean(data[ceny,cenx,0,cpos_arr[0],int(scan)]) #mean of central 1k x 1k of continuum stokes I - #I_c = np.mean(data[50:500,700:1700,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun north limb - #I_c = np.mean(data[1500:2000,800:1300,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun south limb - #I_c = np.mean(data[350:1700,200:900,0,cpos_arr[0],int(scan)]) # West limb - limb_copy = np.copy(data) - - #from Daniele Calchetti - - if limb is not None: - if limb == 'N': - limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = True) - if limb == 'S': - limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = False) - if limb == 'W': - limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = True) - if limb == 'E': - limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = False) - - limb_temp = np.where(limb_temp>0,1,0) - Ic_temp = np.where(Ic_temp>0,1,0) - - data[:,:,:,:,scan] = data[:,:,:,:,scan] * limb_temp[:,:,np.newaxis,np.newaxis] - limb_mask[...,scan] = limb_temp - else: - Ic_temp = np.zeros(data_size) - Ic_temp[ceny,cenx] = 1 - Ic_temp = np.where(Ic_temp>0,1,0) - - if fs_c: - Ic_temp *= field_stop - - Ic_temp = np.array(Ic_temp, dtype=bool) - Ic_mask[...,scan] = Ic_temp - I_c[scan] = np.mean(data[Ic_temp,0,cpos_arr[0],int(scan)]) - data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c[scan] - - # if out_intermediate: - # data_demod = data.copy() - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Stokes Normalising time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - else: - print(" ") - printc('-->>>>>>> No normalising Stokes mode',color=bcolors.WARNING) - - - #----------------- - # CROSS-TALK CALCULATION - #----------------- - - if ItoQUV: - - print(" ") - printc('-->>>>>>> Cross-talk correction I to Q,U,V ',color=bcolors.OKGREEN) - - start_time = time.time() - - num_of_scans = data_shape[-1] - - slope, offset = 0, 1 - q, u, v = 0, 1, 2 - CTparams = np.zeros((2,3,number_of_scans)) - - for scan, scan_hdr in enumerate(hdr_arr): - printc(f' ---- >>>>> CT parameters computation of data scan number: {scan} .... ',color=bcolors.OKGREEN) - ctalk_params = crosstalk_auto_ItoQUV(data[...,scan],cpos_arr[scan],0,roi=Ic_mask[...,scan]) - CTparams[...,scan] = ctalk_params - - if 'CAL_CRT0' in scan_hdr: #check to make sure the keywords exist - - scan_hdr['CAL_CRT0'] = round(ctalk_params[slope,q],4) #I-Q slope - scan_hdr['CAL_CRT2'] = round(ctalk_params[slope,u],4) #I-U slope - scan_hdr['CAL_CRT4'] = round(ctalk_params[slope,v],4) #I-V slope - - scan_hdr['CAL_CRT1'] = round(ctalk_params[offset,q],4) #I-Q offset - scan_hdr['CAL_CRT3'] = round(ctalk_params[offset,u],4) #I-U offset - scan_hdr['CAL_CRT5'] = round(ctalk_params[offset,v],4) #I-V offset - - try: - data = CT_ItoQUV(data, CTparams, norm_stokes, cpos_arr, Ic_mask) - except Exception: - print("There was an issue applying the I -> Q,U,V cross talk correction") - if 'Ic_mask' not in vars(): - print("This could be because 'norm_f' was not set to True") - if data.shape[:2] == (2048,2048): - response = input("The input data is 2k x 2k \n Are all the input data files disk centre pointing? [y/n]") - if response == 'y' or response == 'Y': - try: - Ic_mask = np.zeros(data_size) - Ic_mask[ceny,cenx] = 1 - Ic_mask = np.where(Ic_mask>0,1,0) - Ic_mask = np.array(Ic_mask, dtype = bool) - data = CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask) - except Exception: - print("The issue could not be overcome\n Please check the input config file\n Aborting") - exit() - else: - raise KeyError("Response was not 'y' or 'Y'\n 'norm_f' keyword in input config file not set to True\n Aborting") - else: - raise KeyError("The issue could not be overcome as the Input data is not 2k x 2k\n 'norm_f' keyword in input config file not set to True\n Aborting") - else: - raise KeyError("'norm_f' keyword in input config file not set to True \n Aborting") - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- I -> Q,U,V cross talk correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - data *= field_stop[rows,cols, np.newaxis, np.newaxis, np.newaxis] - # DC change 20211019 only for limb - if limb is not None: - data *= limb_mask[rows,cols, np.newaxis, np.newaxis] - - else: - print(" ") - printc('-->>>>>>> No ItoQUV mode',color=bcolors.WARNING) - - - #----------------- - #CHECK FOR INFs - #----------------- - - data[np.isinf(data)] = 0 - data[np.isnan(data)] = 0 - - - #----------------- - #WRITE OUT STOKES VECTOR - #----------------- - - #these two ifs need to be outside out_stokes_file if statement - needed for inversion - if out_dir[-1] != "/": - print("Desired Output directory missing / character, will be added") - out_dir = out_dir + "/" - - #check if the output directory exists, if not, create it - if not os.path.exists(out_dir): - print(f"{out_dir} does not exist -->>>>>>> Creating it") - os.makedirs(out_dir) - - - if out_stokes_file: - - print(" ") - printc('Saving demodulated data to one _reduced.fits file per scan') - - if out_stokes_filename is not None: - - if isinstance(out_stokes_filename,str): - out_stokes_filename = [out_stokes_filename] - - if int(len(out_stokes_filename)) == int(data_shape[-1]): - scan_name_list = out_stokes_filename - scan_name_defined = True - else: - print("Input demod filenames do not match the number of input arrays, reverting to default naming") - scan_name_defined = False - else: - scan_name_defined = False - - if not scan_name_defined: #check if already defined by input, otherwise generate - scan_name_list = check_filenames(data_f) - - - for count, scan in enumerate(data_f): - - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_reduced.fits") - hdu_list[0].data = data[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_reduced.fits', overwrite=True) - - # DC change 20211014 - """ - if out_intermediate: - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_dark_corrected.fits") - hdu_list[0].data = data_darkc[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_dark_corrected.fits', overwrite=True) - - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") - hdu_list[0].data = data_flatc[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) - - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_demodulated.fits") - hdu_list[0].data = data_demod[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) - """ - - # with fits.open(scan) as hdu_list: - # hdu_list[0].data = limb_copy - # hdu_list.writeto(out_dir+scan_name_list[count]+'_limb_fit_input.fits', overwrite=True) - - else: - print(" ") - #check if already defined by input, otherwise generate - scan_name_list = check_filenames(data_f) - printc('-->>>>>>> No output demod file mode',color=bcolors.WARNING) - - #----------------- - # INVERSION OF DATA WITH CMILOS - #----------------- - - if rte == 'RTE' or rte == 'CE' or rte == 'CE+RTE' or rte == 'RTE_seq': - - #check out_dir has "/" character - if out_dir[-1] != "/": - print("Desired Output directory missing / character, will be added") - out_dir = out_dir + "/" - - - if limb is not None: - mask = limb_mask*field_stop[...,np.newaxis] - else: - mask = np.ones((data_size[0],data_size[1],data_shape[-1]))*field_stop[...,np.newaxis] - - if p_milos: - - try: - pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) - - except ValueError: - print("Running CMILOS instead!") - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) - - else: - if cmilos_fits_opt: - - cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) - else: - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) - - else: - print(" ") - printc('-->>>>>>> No RTE Inversion mode',color=bcolors.WARNING) - - - #----------------- - # SAVING CONFIG FILE - #----------------- - - if config: - print(" ") - printc('-->>>>>>> Saving copy of input config file ',color=bcolors.OKGREEN) - - dt = datetime.datetime.fromtimestamp(overall_time) - runtime = dt.strftime("%d_%m_%YT%H_%M_%S") - - json.dump(input_dict, open(out_dir + f"config_file_{runtime}.json", "w")) - - print(" ") - printc('--------------------------------------------------------------',color=bcolors.OKGREEN) - printc(f'------------ Reduction Complete: {np.round(time.time() - overall_time,3)} seconds',color=bcolors.OKGREEN) - printc('--------------------------------------------------------------',color=bcolors.OKGREEN) - - - if flat_c: - return data, flat - else: - return data diff --git a/hrt_pipe_sub.py b/hrt_pipe_sub.py deleted file mode 100644 index 27aefd1..0000000 --- a/hrt_pipe_sub.py +++ /dev/null @@ -1,1121 +0,0 @@ -import numpy as np -from astropy.io import fits -from scipy.ndimage import gaussian_filter -from operator import itemgetter -from utils import * -import os -import time -import subprocess - -def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_exists, imgdirx_flipped, cpos_arr) -> np.ndarray: - """ - load, scale, flip and correct flat - """ - print(" ") - printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) - - start_time = time.time() - - # flat from IP-5 - if '0024151020000' in flat_f or '0024150020000' in flat_f: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=False) - else: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=scale_data) - - if 'IMGDIRX' in header_flat: - header_fltdirx_exists = True - fltdirx_flipped = str(header_flat['IMGDIRX']) - else: - header_fltdirx_exists = False - fltdirx_flipped = 'NO' - - print(f"Flat field shape is {flat.shape}") - # correction based on science data - see if flat and science are both flipped or not - flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) - - flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] - flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states - flat = np.moveaxis(flat, 2,-1) - - print(flat.shape) - - _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position - - print(f"The continuum position of the flat field is at {cpos_f} index position") - - #-------- - # test if the science and flat have continuum at same position - #-------- - - flat = compare_cpos(flat,cpos_f,cpos_arr[0]) - - flat_pmp_temp = str(header_flat['HPMPTSP1']) - - print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") - - #-------- - # correct for missing line in particular flat field - #-------- - - if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' - print("This flat has a missing line - filling in with neighbouring pixels") - flat_copy = flat.copy() - flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) - - del flat_copy - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return flat - - -def load_dark(dark_f) -> np.ndarray: - """ - loads dark field from given path - """ - print(" ") - printc('-->>>>>>> Reading Darks',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - dark,_ = get_data(dark_f) - - dark_shape = dark.shape - - if dark_shape != (2048,2048): - - if dark.ndim > 2: - printc("Dark Field Input File has more dimensions than the expected 2048,2048 format: {}",dark_f,color=bcolors.WARNING) - raise ValueError - - printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) - printc("Attempting to correct ",color=bcolors.WARNING) - - - try: - if dark_shape[0] > 2048: - dark = dark[dark_shape[0]-2048:,:] - - except Exception: - printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) - raise ValueError - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return dark - - except Exception: - printc("ERROR, Unable to open and process darks file: {}",dark_f,color=bcolors.FAIL) - - -def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: - """ - subtracts dark field from flat field and science data - """ - print(" ") - print("-->>>>>>> Subtracting dark field") - - start_time = time.time() - - data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] - #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Dark Field correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data, flat - - -def normalise_flat(flat, flat_f, ceny, cenx) -> np.ndarray: - """ - normalise flat fields at each wavelength position to remove the spectral line - """ - print(" ") - printc('-->>>>>>> Normalising Flats',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - norm_fac = np.mean(flat[ceny,cenx, :, :], axis = (0,1))[np.newaxis, np.newaxis, ...] #mean of the central 1k x 1k - flat /= norm_fac - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Normalising flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return flat - - except Exception: - printc("ERROR, Unable to normalise the flat fields: {}",flat_f,color=bcolors.FAIL) - - -def demod_hrt(data,pmp_temp, verbose = True) -> np.ndarray: - ''' - Use constant demodulation matrices to demodulate input data - ''' - if pmp_temp == '50': - demod_data = np.array([[ 0.28037298, 0.18741922, 0.25307596, 0.28119895], - [ 0.40408596, 0.10412157, -0.7225681, 0.20825675], - [-0.19126636, -0.5348939, 0.08181918, 0.64422774], - [-0.56897295, 0.58620095, -0.2579202, 0.2414017 ]]) - - elif pmp_temp == '40': - demod_data = np.array([[ 0.26450154, 0.2839626, 0.12642948, 0.3216773 ], - [ 0.59873885, 0.11278069, -0.74991184, 0.03091451], - [ 0.10833212, -0.5317737, -0.1677862, 0.5923593 ], - [-0.46916953, 0.47738808, -0.43824592, 0.42579797]]) - - else: - printc("Demodulation Matrix for PMP TEMP of {pmp_temp} deg is not available", color = bcolors.FAIL) - if verbose: - printc(f'Using a constant demodulation matrix for a PMP TEMP of {pmp_temp} deg',color = bcolors.OKGREEN) - - demod_data = demod_data.reshape((4,4)) - shape = data.shape - demod = np.tile(demod_data, (shape[0],shape[1],1,1)) - - if data.ndim == 5: - #if data array has more than one scan - data = np.moveaxis(data,-1,0) #moving number of scans to first dimension - - data = np.matmul(demod,data) - data = np.moveaxis(data,0,-1) #move scans back to the end - - elif data.ndim == 4: - #for if data has just one scan - data = np.matmul(demod,data) - - return data, demod - - -def unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode,clean_f,pol_end=4,verbose=True): - """ - unsharp masks the flat fields to blur our polarimetric structures due to solar rotation - clean_f = ['blurring', 'fft'] - """ - flat_demod, demodM = demod_hrt(flat, flat_pmp_temp,verbose) - - norm_factor = np.mean(flat_demod[512:1536,512:1536,0,cpos_arr[0]]) - - flat_demod /= norm_factor - - new_demod_flats = np.copy(flat_demod) - -# b_arr = np.zeros((2048,2048,3,5)) - - if cpos_arr[0] == 0: - wv_range = range(1,6) - - elif cpos_arr[0] == 5: - wv_range = range(5) - - if clean_mode == "QUV": - start_clean_pol = 1 - if verbose: - print("Unsharp Masking Q,U,V") - - elif clean_mode == "UV": - start_clean_pol = 2 - if verbose: - print("Unsharp Masking U,V") - - elif clean_mode == "V": - start_clean_pol = 3 - if verbose: - print("Unsharp Masking V") - - if clean_f == 'blurring': - blur = lambda a: gaussian_filter(a,sigma) - elif clean_f == 'fft': - x = np.fft.fftfreq(2048,1) - fftgaus2d = np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[:,np.newaxis] * np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[np.newaxis] - blur = lambda a : (np.fft.ifftn(fftgaus2d*np.fft.fftn(a.copy()))).real - - for pol in range(start_clean_pol,pol_end): - - for wv in wv_range: #not the continuum - - a = np.copy(np.clip(flat_demod[:,:,pol,wv], -0.02, 0.02)) - b = a - blur(a) -# b_arr[:,:,pol-1,wv-1] = b - c = a - b - - new_demod_flats[:,:,pol,wv] = c - - invM = np.linalg.inv(demodM) - - return np.matmul(invM, new_demod_flats*norm_factor) - - -def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: - """ - correct science data with flat fields - """ - print(" ") - printc('-->>>>>>> Correcting Flatfield',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - if flat_states == 6: - - printc("Dividing by 6 flats, one for each wavelength",color=bcolors.OKGREEN) - - tmp = np.mean(flat,axis=-2) #avg over pol states for the wavelength - - return data / tmp[rows,cols, np.newaxis, :, np.newaxis] - - - elif flat_states == 24: - - printc("Dividing by 24 flats, one for each image",color=bcolors.OKGREEN) - - return data / flat[rows,cols, :, :, np.newaxis] #only one new axis for the scans - - elif flat_states == 4: - - printc("Dividing by 4 flats, one for each pol state",color=bcolors.OKGREEN) - - tmp = np.mean(flat,axis=-1) #avg over wavelength - - return data / tmp[rows,cols, :, np.newaxis, np.newaxis] - else: - print(" ") - printc('-->>>>>>> Unable to apply flat correction. Please insert valid flat_states',color=bcolors.WARNING) - - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data - - except: - printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) - - - -def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): - """ - applies prefilter correction - adapted from SPGPylibs - """ - def _get_v1_index1(x): - index1, v1 = min(enumerate([abs(i) for i in x]), key=itemgetter(1)) - return v1, index1 - - data_shape = data.shape - - for scan in range(data_shape[-1]): - - voltage_list = voltagesData_arr[scan] - - for wv in range(6): - - v = voltage_list[wv] - - vdif = [v - pf for pf in prefilter_voltages] - - v1, index1 = _get_v1_index1(vdif) - - if vdif[index1] >= 0: - v2 = vdif[index1 + 1] - index2 = index1 + 1 - - else: - v2 = vdif[index1-1] - index2 = index1 - 1 - - imprefilter = (prefilter[:,:, index1]*v1 + prefilter[:,:, index2]*v2)/(v1+v2) #interpolation between nearest voltages - - data[:,:,:,wv,scan] /= imprefilter[...,np.newaxis] - - return data - -def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: - """ - apply field stop mask to the science data - """ - print(" ") - printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) - - start_time = time.time() - - field_stop,_ = load_fits('../field_stop/HRT_field_stop.fits') - - field_stop = np.where(field_stop > 0,1,0) - - if header_imgdirx_exists: - if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software - field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction - - data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data, field_stop - -def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): - import random, statistics - from scipy.optimize import curve_fit - def linear(x,a,b): - return a*x + b - my = [] - sy = [] - - x = data_demod[roi>0,0,cpos].flatten() - ids = np.logical_and(x > limit, x < 1.5) - x = x[ids].flatten() - - N = x.size - idx = random.sample(range(N),npoints) - mx = x[idx].mean() - sx = x[idx].std() - xp = np.linspace(x.min(), x.max(), 100) - - A = np.vstack([x, np.ones(len(x))]).T - - # I to Q - yQ = data_demod[roi>0,1,wl].flatten() - yQ = yQ[ids].flatten() - my.append(yQ[idx].mean()) - sy.append(yQ[idx].std()) - cQ = curve_fit(linear,x,yQ,p0=[0,0])[0] - pQ = np.poly1d(cQ) - - # I to U - yU = data_demod[roi>0,2,wl].flatten() - yU = yU[ids].flatten() - my.append(yU[idx].mean()) - sy.append(yU[idx].std()) - cU = curve_fit(linear,x,yU,p0=[0,0])[0] - pU = np.poly1d(cU) - - # I to V - yV = data_demod[roi>0,3,wl].flatten() - yV = yV[ids].flatten() - my.append(yV[idx].mean()) - sy.append(yV[idx].std()) - cV = curve_fit(linear,x,yV,p0=[0,0])[0] - pV = np.poly1d(cV) - - if verbose: - - PLT_RNG = 3 - fig, ax = plt.subplots(figsize=(8, 8)) - ax.scatter(x[idx],yQ[idx],color='red',alpha=0.6,s=10) - ax.plot(xp, pQ(xp), color='red', linestyle='dashed',linewidth=3.0) - - ax.scatter(x[idx],yU[idx],color='blue',alpha=0.6,s=10) - ax.plot(xp, pU(xp), color='blue', linestyle='dashed',linewidth=3.0) - - ax.scatter(x[idx],yV[idx],color='green',alpha=0.6,s=10) - ax.plot(xp, pV(xp), color='green', linestyle='dashed',linewidth=3.0) - - ax.set_xlim([mx - PLT_RNG * sx,mx + PLT_RNG * sx]) - ax.set_ylim([min(my) - 1.8*PLT_RNG * statistics.mean(sy),max(my) + PLT_RNG * statistics.mean(sy)]) - ax.set_xlabel('Stokes I') - ax.set_ylabel('Stokes Q/U/V') - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.4*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4), style='italic',bbox={'facecolor': 'red', 'alpha': 0.1, 'pad': 1}, fontsize=15) - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.55*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4), style='italic',bbox={'facecolor': 'blue', 'alpha': 0.1, 'pad': 1}, fontsize=15) - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.7*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4), style='italic',bbox={'facecolor': 'green', 'alpha': 0.1, 'pad': 1}, fontsize=15) -# fig.show() - - print('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4)) - print('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4)) - print('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4)) - -# return cQ,cU,cV, (idx,x,xp,yQ,yU,yV,pQ,pU,pV,mx,sx,my,sy) - else: - ct = np.asarray((cQ,cU,cV)).T - return ct - -def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): - """ - performs cross talk correction for I -> Q,U,V - """ - before_ctalk_data = np.copy(data) - data_shape = data.shape - -# ceny = slice(data_shape[0]//2 - data_shape[0]//4, data_shape[0]//2 + data_shape[0]//4) -# cenx = slice(data_shape[1]//2 - data_shape[1]//4, data_shape[1]//2 + data_shape[1]//4) - - cont_stokes = np.ones(data_shape[-1]) - printc(data_shape[-1],color=bcolors.WARNING) - printc(Ic_mask.shape,color=bcolors.WARNING) - for scan in range(data_shape[-1]): - cont_stokes[scan] = np.mean(data[Ic_mask[...,scan],0,cpos_arr[0],scan]) - print('here1') - for i in range(6): - -# stokes_i_wv_avg = np.mean(data[ceny,cenx,0,i,:], axis = (0,1)) - stokes_i_wv_avg = np.ones(data_shape[-1]) - for scan in range(data_shape[-1]): - stokes_i_wv_avg[scan] = np.mean(data[Ic_mask[...,scan],0,i,scan]) - - print('here2') - if norm_stokes: - #if normed, applies normalised offset to normed stokes - - tmp_param = ctalk_params*np.divide(stokes_i_wv_avg,cont_stokes) - - q_slope = tmp_param[0,0,:] - u_slope = tmp_param[0,1,:] - v_slope = tmp_param[0,2,:] - - q_int = tmp_param[1,0,:] - u_int = tmp_param[1,1,:] - v_int = tmp_param[1,2,:] - - data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int - - data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int - - data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int - print('here3') - - else: - #if not normed, applies raw offset cross talk correction to raw stokes counts - - tmp_param = ctalk_params[0,:,:]*np.divide(stokes_i_wv_avg,cont_stokes) - - q_slope = tmp_param[0,:] - u_slope = tmp_param[1,:] - v_slope = tmp_param[2,:] - - q_int = ctalk_params[1,0,:] - u_int = ctalk_params[1,1,:] - v_int = ctalk_params[1,2,:] - - data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int*stokes_i_wv_avg - - data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int*stokes_i_wv_avg - - data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int*stokes_i_wv_avg - - return data - - -def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): - """ - RTE inversion using CMILOS - """ - print(" ") - printc('-->>>>>>> RUNNING CMILOS ',color=bcolors.OKGREEN) - - try: - CMILOS_LOC = os.path.realpath(__file__) - - CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters - - if os.path.isfile(CMILOS_LOC+'milos'): - printc("Cmilos executable located at:", CMILOS_LOC,color=bcolors.WARNING) - - else: - raise ValueError('Cannot find cmilos:', CMILOS_LOC) - - except ValueError as err: - printc(err.args[0],color=bcolors.FAIL) - printc(err.args[1],color=bcolors.FAIL) - return - - wavelength = 6173.3354 - - for scan in range(int(data_shape[-1])): - - start_time = time.time() - - file_path = data_f[scan] - wave_axis = wve_axis_arr[scan] - hdr = hdr_arr[scan] - - #must invert each scan independently, as cmilos only takes in one dataset at a time - - #get wave_axis from the hdr information of the science scans - if cpos_arr[0] == 0: - shift_w = wave_axis[3] - wavelength - elif cpos_arr[0] == 5: - shift_w = wave_axis[2] - wavelength - # DC TEST - wave_axis = wave_axis - shift_w - - print('It is assumed the wavelength array is given by the hdr') - #print(wave_axis,color = bcolors.WARNING) - print("Wave axis is: ", (wave_axis - wavelength)*1000.) - print('Saving data into dummy_in.txt for RTE input') - - sdata = data[:,:,:,:,scan] - y,x,p,l = sdata.shape - #print(y,x,p,l) - - filename = 'dummy_in.txt' - with open(filename,"w") as f: - for i in range(x): - for j in range(y): - for k in range(l): - f.write('%e %e %e %e %e \n' % (wave_axis[k],sdata[j,i,0,k],sdata[j,i,1,k],sdata[j,i,2,k],sdata[j,i,3,k])) #wv, I, Q, U, V - del sdata - - printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) - - cmd = CMILOS_LOC+"./milos" - cmd = fix_path(cmd) - - if rte == 'RTE': - rte_on = subprocess.call(cmd+" 6 15 0 0 dummy_in.txt > dummy_out.txt",shell=True) - if rte == 'CE': - rte_on = subprocess.call(cmd+" 6 15 2 0 dummy_in.txt > dummy_out.txt",shell=True) - if rte == 'CE+RTE': - rte_on = subprocess.call(cmd+" 6 15 1 0 dummy_in.txt > dummy_out.txt",shell=True) - - #print(rte_on) - - printc(' ---- >>>>> Reading results.... ',color=bcolors.OKGREEN) - del_dummy = subprocess.call("rm dummy_in.txt",shell=True) - #print(del_dummy) - - res = np.loadtxt('dummy_out.txt') - npixels = res.shape[0]/12. - #print(npixels) - #print(npixels/x) - result = np.zeros((12,y*x)).astype(float) - rte_invs = np.zeros((12,y,x)).astype(float) - for i in range(y*x): - result[:,i] = res[i*12:(i+1)*12] - result = result.reshape(12,y,x) - result = np.einsum('ijk->ikj', result) - rte_invs = result - del result - rte_invs_noth = np.copy(rte_invs) - - """ - From 0 to 11 - Counter (PX Id) - Iterations - Strength - Inclination - Azimuth - Eta0 parameter - Doppler width - Damping - Los velocity - Constant source function - Slope source function - Minimum chisqr value - """ - - noise_in_V = np.mean(data[:,:,3,cpos_arr[0],:]) - low_values_flags = np.max(np.abs(data[:,:,3,:,scan]),axis=-1) < noise_in_V # Where values are low - - rte_invs[2,low_values_flags] = 0 - rte_invs[3,low_values_flags] = 0 - rte_invs[4,low_values_flags] = 0 - - #np.savez_compressed(out_dir+'_RTE', rte_invs=rte_invs, rte_invs_noth=rte_invs_noth) - - del_dummy = subprocess.call("rm dummy_out.txt",shell=True) - #print(del_dummy) - - """ - #vlos S/C vorrection - v_x, v_y, v_z = hdr['HCIX_VOB']/1000, hdr['HCIY_VOB']/1000, hdr['HCIZ_VOB']/1000 - - #need line of sight velocity, should be total HCI velocity in km/s, with sun at origin. - #need to take care for velocities moving towards the sun, (ie negative) #could use continuum position as if towards or away - - if cpos_arr[scan] == 5: #moving away, redshifted - dir_factor = 1 - - elif cpos_arr[scan] == 0: #moving towards, blueshifted - dir_factor == -1 - - v_tot = dir_factor*math.sqrt(v_x**2 + v_y**2+v_z**2) #in km/s - - rte_invs_noth[8,:,:] = rte_invs_noth[8,:,:] - v_tot - """ - - rte_data_products = np.zeros((6,rte_invs_noth.shape[1],rte_invs_noth.shape[2])) - - rte_data_products[0,:,:] = rte_invs_noth[9,:,:] + rte_invs_noth[10,:,:] #continuum - rte_data_products[1,:,:] = rte_invs_noth[2,:,:] #b mag strength - rte_data_products[2,:,:] = rte_invs_noth[3,:,:] #inclination - rte_data_products[3,:,:] = rte_invs_noth[4,:,:] #azimuth - rte_data_products[4,:,:] = rte_invs_noth[8,:,:] #vlos - rte_data_products[5,:,:] = rte_invs_noth[2,:,:]*np.cos(rte_invs_noth[3,:,:]*np.pi/180.) #blos - - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 - - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - else: - if isinstance(out_rte_filename, list): - filename_root = out_rte_filename[scan] - - elif isinstance(out_rte_filename, str): - filename_root = out_rte_filename - - else: - filename_root = str(file_path.split('.fits')[0][-10:]) - print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].hdrheader= hdr - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- CMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - -def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): - """ - RTE inversion using CMILOS - """ - print(" ") - printc('-->>>>>>> RUNNING CMILOS ',color=bcolors.OKGREEN) - - try: - CMILOS_LOC = os.path.realpath(__file__) - - CMILOS_LOC = CMILOS_LOC[:-15] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters - - if os.path.isfile(CMILOS_LOC+'milos'): - printc("Cmilos-fits executable located at:", CMILOS_LOC,color=bcolors.WARNING) - - else: - raise ValueError('Cannot find cmilos-fits:', CMILOS_LOC) - - except ValueError as err: - printc(err.args[0],color=bcolors.FAIL) - printc(err.args[1],color=bcolors.FAIL) - return - - wavelength = 6173.3354 - - for scan in range(int(data_shape[-1])): - - start_time = time.time() - - file_path = data_f[scan] - wave_axis = wve_axis_arr[scan] - hdr = hdr_arr[scan] - - #must invert each scan independently, as cmilos only takes in one dataset at a time - - #get wave_axis from the hdr information of the science scans - if cpos_arr[0] == 0: - shift_w = wave_axis[3] - wavelength - elif cpos_arr[0] == 5: - shift_w = wave_axis[2] - wavelength - - wave_axis = wave_axis - shift_w - - print('It is assumed the wavelength array is given by the hdr') - #print(wave_axis,color = bcolors.WARNING) - print("Wave axis is: ", (wave_axis - wavelength)*1000.) - print('Saving data into dummy_in.txt for RTE input') - - sdata = data[:,:,:,:,scan] - y,x,p,l = sdata.shape - - #create hdr with wavelength positions - hdr = fits.Header() - print(wave_axis[0]) - hdr['LAMBDA0'] = wave_axis[0]#needs it in Angstrom 6173.1 etc - hdr['LAMBDA1'] = wave_axis[1] - hdr['LAMBDA2'] = wave_axis[2] - hdr['LAMBDA3'] = wave_axis[3] - hdr['LAMBDA4'] = wave_axis[4] - hdr['LAMBDA5'] = wave_axis[5] - - - #write out data to temp fits for cmilos-fits input - input_arr = np.transpose(sdata, axes = (3,2,0,1)) #must transpose due to cfitsio (wl,pol,y,x) #3201 originally - - # DC CHANGE (same number of digits of cmilos) -# hdr['LAMBDA0'] = float('%e' % wave_axis[0])#needs it in Angstrom 6173.1 etc -# hdr['LAMBDA1'] = float('%e' % wave_axis[1]) -# hdr['LAMBDA2'] = float('%e' % wave_axis[2]) -# hdr['LAMBDA3'] = float('%e' % wave_axis[3]) -# hdr['LAMBDA4'] = float('%e' % wave_axis[4]) -# hdr['LAMBDA5'] = float('%e' % wave_axis[5]) -# printc('-->>>>>>> CHANGING DATA PRECISION ',color=bcolors.OKGREEN) -# for w in range(l): -# for s in range(p): -# for i in range(y): -# for j in range(x): -# input_arr[w,s,i,j] = float('%e' % input_arr[w,s,i,j]) - # DC CHANGE END - - hdu1 = fits.PrimaryHDU(data=input_arr, header = hdr) - - #mask - mask = np.ones((sdata.shape[0],sdata.shape[1])) #change this for fdt - hdu2 = fits.ImageHDU(data=mask) - - #write out to temp fits - hdul_tmp = fits.HDUList([hdu1, hdu2]) - hdul_tmp.writeto(out_dir+'temp_cmilos_io.fits', overwrite=True) - - del sdata - - printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) - - cmd = CMILOS_LOC+"milos" - #cmd = fix - #fix_path(cmd) - print(cmd) - - if rte == 'RTE': - rte_on = subprocess.call(cmd+f" 6 15 0 {out_dir+'temp_cmilos_io.fits'}",shell=True) - if rte == 'CE': - rte_on = subprocess.call(cmd+f" 6 15 2 {out_dir+'temp_cmilos_io.fits'}",shell=True) - if rte == 'CE+RTE': - rte_on = subprocess.call(cmd+f" 6 15 1 {out_dir+'temp_cmilos_io.fits'}",shell=True) - - print(rte_on) - - printc(' ---- >>>>> Reading results.... ',color=bcolors.OKGREEN) - #print(del_dummy) - - with fits.open(out_dir+'temp_cmilos_io.fits') as hdu_list: - rte_out = hdu_list[0].data - #hdu_list.writeto(out_dir+'rte_out.fits', overwrite=True) - - del input_arr - - """ - From 0 to 11 - Iterations - Strength - Inclination - Azimuth - Eta0 parameter - Doppler width - Damping/aa - Los velocity - alfa? Counter PID? - Constant source function - Slope source function - Minimum chisqr value - """ - - """ - Direct from cmilos-fits/milos.c - inv->iter = malloc(npix*sizeof(int)); - inv->B = malloc(npix*sizeof(double)); - inv->gm = malloc(npix*sizeof(double)); - inv->az = malloc(npix*sizeof(double)); - inv->eta0 = malloc(npix*sizeof(double)); - inv->dopp = malloc(npix*sizeof(double)); - inv->aa = malloc(npix*sizeof(double)); - inv->vlos = malloc(npix*sizeof(double)); //km/s - inv->alfa = malloc(npix*sizeof(double)); //stay light factor - inv->S0 = malloc(npix*sizeof(double)); - inv->S1 = malloc(npix*sizeof(double)); - inv->nchisqrf = malloc(npix*sizeof(double)); - - """ - - """ - noise_in_V = np.mean(data[:,:,3,cpos_arr[0],:]) - low_values_flags = np.max(np.abs(data[:,:,3,:,scan]),axis=-1) < noise_in_V # Where values are low - - rte_out[2,low_values_flags] = 0 #not sure about 2,3,4 indexing here - rte_out[3,low_values_flags] = 0 - rte_out[4,low_values_flags] = 0 - """ - - rte_data_products = np.zeros((6,rte_out.shape[1],rte_out.shape[2])) - - rte_data_products[0,:,:] = rte_out[9,:,:] + rte_out[10,:,:] #continuum - rte_data_products[1,:,:] = rte_out[1,:,:] #b mag strength - rte_data_products[2,:,:] = rte_out[2,:,:] #inclination - rte_data_products[3,:,:] = rte_out[3,:,:] #azimuth - rte_data_products[4,:,:] = rte_out[7,:,:] #vlos - rte_data_products[5,:,:] = rte_out[1,:,:]*np.cos(rte_out[2,:,:]*np.pi/180.) #blos - - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 - - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - else: - if isinstance(out_rte_filename, list): - filename_root = out_rte_filename[scan] - - elif isinstance(out_rte_filename, str): - filename_root = out_rte_filename - - else: - filename_root = str(file_path.split('.fits')[0][-10:]) - print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - - -def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): - """ - RTE inversion using PMILOS - """ - print(" ") - printc('-->>>>>>> RUNNING PMILOS ',color=bcolors.OKGREEN) - - try: - PMILOS_LOC = os.path.realpath(__file__) - - PMILOS_LOC = PMILOS_LOC[:-15] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py - - if os.path.isfile(PMILOS_LOC+'pmilos.x'): - printc("Pmilos executable located at:", PMILOS_LOC,color=bcolors.WARNING) - - else: - raise ValueError('Cannot find pmilos:', PMILOS_LOC) - - except ValueError as err: - printc(err.args[0],color=bcolors.FAIL) - printc(err.args[1],color=bcolors.FAIL) - return - - wavelength = 6173.3354 - - for scan in range(int(data_shape[-1])): - - start_time = time.time() - - file_path = data_f[scan] - wave_axis = wve_axis_arr[scan] - - #must invert each scan independently, as cmilos only takes in one dataset at a time - - #get wave_axis from the hdr information of the science scans - if cpos_arr[0] == 0: - shift_w = wave_axis[3] - wavelength - elif cpos_arr[0] == 5: - shift_w = wave_axis[2] - wavelength - - wave_axis = wave_axis - shift_w - - print('It is assumed the wavelength array is given by the hdr') - #print(wave_axis,color = bcolors.WARNING) - print("Wave axis is: ", (wave_axis - wavelength)*1000.) - print('Saving data into ./p-milos/run/data/input_tmp.fits for pmilos RTE input') - - #write wavelengths to wavelength.fits file for the settings - - wave_input = np.zeros((2,6)) #cfitsio reads dimensions in opposite order - wave_input[0,:] = 1 - wave_input[1,:] = wave_axis - - print(wave_axis) - - hdr = fits.Header() - - primary_hdu = fits.PrimaryHDU(wave_input, header = hdr) - hdul = fits.HDUList([primary_hdu]) - hdul.writeto(f'./p-milos/run/wavelength_tmp.fits', overwrite=True) - - sdata = data[:,:,:,:,scan].T - sdata = sdata.astype(np.float32) - #create input fits file for pmilos - hdr = fits.Header() - - hdr['CTYPE1'] = 'HPLT-TAN' - hdr['CTYPE2'] = 'HPLN-TAN' - hdr['CTYPE3'] = 'STOKES' #check order of stokes - hdr['CTYPE4'] = 'WAVE-GRI' - - primary_hdu = fits.PrimaryHDU(sdata, header = hdr) - hdul = fits.HDUList([primary_hdu]) - hdul.writeto(f'./p-milos/run/data/input_tmp.fits', overwrite=True) - - if rte == 'RTE': - cmd = "mpiexec -n 64 ../pmilos.x pmilos.minit" #../milos.x pmilos.mtrol" ## - - if rte == 'CE': - cmd = "mpiexec -np 16 ../pmilos.x pmilos_ce.minit" - - if rte == 'CE+RTE': - print("CE+RTE not possible on PMILOS, performing RTE instead") - cmd = "mpiexec -np 16 ../pmilos.x pmilos.minit" - - if rte == 'RTE_seq': - cmd = '../milos.x pmilos.mtrol' - - del sdata - #need to change settings for CE or CE+RTE in the pmilos.minit file here - - printc(f' ---- >>>>> Inverting data scan number: {scan} .... ',color=bcolors.OKGREEN) - - cwd = os.getcwd() - os.chdir("./p-milos/run/") - rte_on = subprocess.call(cmd,shell=True) - os.chdir(cwd) - - if rte == 'CE': - out_file = 'inv__mod_ce.fits' # not sure about this one - - else: - out_file = 'inv__mod.fits' #only when one datacube and 16 processors - - with fits.open(f'./p-milos/run/results/{out_file}') as hdu_list: - result = hdu_list[0].data - - #del_dummy = subprocess.call(f"rm ./p-milos/run/results/{out_file}.fits",shell=True) - del_dummy = subprocess.call(f"rm ./p-milos/run/results/{out_file}",shell=True) #must delete the output file - - #result has dimensions [rows,cols,13] - result = np.moveaxis(result,0,2) - print(result.shape) - #printc(f' ---- >>>>> You are HERE .... ',color=bcolors.WARNING) - """ - PMILOS Output 13 columns - 0. eta0 = line-to-continuum absorption coefficient ratio - 1. B = magnetic field strength [Gauss] - 2. vlos = line-of-sight velocity [km/s] - 3. dopp = Doppler width [Angstroms] - 4. aa = damping parameter - 5. gm = magnetic field inclination [deg] - 6. az = magnetic field azimuth [deg] - 7. S0 = source function constant - 8. S1 = source function gradient - 9. mac = macroturbulent velocity [km/s] - 10. filling factor of the magnetic component [0-1] - 11. Number of iterations performed - 12. Chisqr value - """ - - rte_data_products = np.zeros((6,result.shape[0],result.shape[1])) - - rte_data_products[0,:,:] = result[:,:,7] + result[:,:,8] #continuum - rte_data_products[2,:,:] = result[:,:,5] #inclination - rte_data_products[3,:,:] = result[:,:,6] #azimuth - rte_data_products[4,:,:] = result[:,:,2] #vlos - rte_data_products[5,:,:] = result[:,:,1]*np.cos(result[:,:,5]*np.pi/180.) #blos - - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 - - #flipping taken care of for the field stop in the hrt_pipe - #printc(f' ---- >>>>> and HERE now .... ',color=bcolors.WARNING) - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - else: - filename_root = out_rte_filename - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) - - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- PMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) -- GitLab From 3f7df63635e8e6b37976b250d2f7aad24ecb796c Mon Sep 17 00:00:00 2001 From: jonas Date: Thu, 18 Nov 2021 15:27:55 +0100 Subject: [PATCH 13/34] pmilos file loc --- src/hrt_pipe_sub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 36322c9..252f1a3 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -945,7 +945,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st try: PMILOS_LOC = os.path.realpath(__file__) - PMILOS_LOC = PMILOS_LOC[:-15] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py + PMILOS_LOC = PMILOS_LOC.split('src/')[0] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py if os.path.isfile(PMILOS_LOC+'pmilos.x'): printc("Pmilos executable located at:", PMILOS_LOC,color=bcolors.WARNING) -- GitLab From 076df5eaf33868c4aa3242485270b594a290d05a Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 11:29:07 +0100 Subject: [PATCH 14/34] env name change --- README.md | 6 +++--- setup.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4184c30..e03a927 100755 --- a/README.md +++ b/README.md @@ -54,14 +54,14 @@ using pip - REQUIRES PYTHON >= 3.6 ```bash pip install -r requirements.txt ``` -OR using conda (Anaconda3) - creates virtual environment called 'dataproc' +OR using conda (Anaconda3) - creates virtual environment called 'hrt_pipeline_env' ```bash conda env create -f environment.yml ``` -4. Activate 'dataproc' +4. Activate 'hrt_pipeline_env' ```bash -source activate dataproc +source activate hrt_pipeline_env ``` 5. Download files - see **DOWNLOAD INPUT FILES** Section diff --git a/setup.sh b/setup.sh index c686870..9624326 100644 --- a/setup.sh +++ b/setup.sh @@ -31,5 +31,5 @@ cd .. conda env create -f environment.yml #pip install -r requrements.txt -source activate dataproc +source activate hrt_pipeline_env -- GitLab From 12d99b4e1410e864dbd19fbc189d70a83edf6972 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 12:22:40 +0100 Subject: [PATCH 15/34] update env --- README.md | 2 +- environment.yml | 4 ++-- setup.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e03a927..25a93f8 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Operating System Required: Linux If running on bob MPS server and you have access -Run bash script - setup.sh - to skip the first four steps +Run bash script - setup.sh - to skip the first 3 steps OTHERWISE: diff --git a/environment.yml b/environment.yml index 5a82a79..69189d5 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: dataproc +name: hrt_pipeline_env channels: - conda-forge - defaults @@ -77,5 +77,5 @@ dependencies: - xz=5.2.5=h7b6447c_0 - zlib=1.2.11=h7b6447c_3 - zstd=1.4.5=h9ceee32_0 -prefix: /home/sinjan/.conda/envs/dataproc +prefix: /home/sinjan/.conda/envs/hrt_pipeline_env diff --git a/setup.sh b/setup.sh index 9624326..71a52d5 100644 --- a/setup.sh +++ b/setup.sh @@ -31,5 +31,5 @@ cd .. conda env create -f environment.yml #pip install -r requrements.txt -source activate hrt_pipeline_env +#source activate hrt_pipeline_env -- GitLab From b05378cd3e1225fe49a0203c0ca29babb0ca31d4 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:12:08 +0100 Subject: [PATCH 16/34] example notebook + updates --- .../hrt_pipeline_notebook-checkpoint.ipynb | 296 +++++++++++++++++ README.md | 19 +- example_input_json.py | 7 +- hrt_pipeline_notebook.ipynb | 297 ++++++++++++++++++ setup.sh | 4 +- src/hrt_pipe.py | 20 +- src/hrt_pipe_sub.py | 10 +- 7 files changed, 634 insertions(+), 19 deletions(-) create mode 100644 .ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb create mode 100644 hrt_pipeline_notebook.ipynb diff --git a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb new file mode 100644 index 0000000..dda12f2 --- /dev/null +++ b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb @@ -0,0 +1,296 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# **PHI-HRT Pipeline**\n", + "\n", + "_____________\n", + "\n", + "Author: Jonas Sinjan (MPS)
\n", + "Contributor: Daniele Calchetti (MPS)\n", + "\n", + "Reductions Steps\n", + "\n", + "1. read in science data (+scaling) open path option + open for several scans at once\n", + "2. read in flat field (+scaling)- accepts only one flat field fits file\n", + "3. read in dark field (+scaling)\n", + "4. apply dark field (to only science - assumes flat is dark fielded)\n", + "5. option to clean flat field with unsharp masking (Stokes QUV, UV or V)\n", + "6. normalise flat field\n", + "7. apply flat field\n", + "8. prefilter correction\n", + "9. apply field stop\n", + "10. demodulate with const demod matrix\n", + "11. normalise to quiet sun\n", + "12. I -> Q,U,V cross talk correction\n", + "13. rte inversion with cmilos\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Download files\n", + "\n", + "(This requires the hrt_pipeline_env environment - or the correct modules installed with pip (see `requirements.txt`)\n", + "\n", + "Options:\n", + "\n", + "1. Can download manually yourself from the PHI Image Database: https://www2.mps.mpg.de/services/proton/phi/imgdb/\n", + "\n", + " Suggested filters on the database for HRT science data: \n", + " - KEYWORD DETECTOR = 'HRT'
\n", + " - Filename\\* like \\*L1_phi-hrt-ilam_date\\*\n", + " \n", + " Once you find the file you want use the Command Line: \n", + " \n", + " ```\n", + " wget --user yourusername --password yourpassword file_web_address_from_database\n", + " gunzip file.gz\n", + " ```\n", + " \n", + "2. Use the provided script in 'downloads' folder (**Benefit: can download multiple files at once**): `downloads/download_from_db.py`\n", + "\n", + " Instructions:\n", + " 1. From the database find the files you wish to download\n", + " 2. Copy the 'Download File List' that the database will generate\n", + " 3. Paste into the `downloads/file_names.txt` file\n", + " 4. Create a `downloads/.env` file with your MPS Windows login:
\n", + " ```text=\n", + " USER_NAME =\n", + " PHIDATAPASSWORD =\n", + " ``` \n", + " 5. Set the **target download folder** in the `download_from_db.py` file\n", + " 6. Run the file (will require dotenv python module to be installed - included in `hrt_pipeline_env`):\n", + " ```text=\n", + " python download_from_db.py\n", + " ```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Create Input JSON (config) file" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "#example\n", + "\n", + "data_path = ['data_one.fits', 'data_two.fits', 'etc.fits...'] \n", + "\n", + "#can have as many files as you like, contintue the list\n", + "\n", + "\"\"\"\n", + "IMPORTANT\n", + "\n", + "- files will be procssed with the same flat, dark\n", + "- must have the same continuum position, pmp temp etc - checks will be run, and pipeline will exit if they fail\n", + "- if data is a limb image, the limb in the FOV must be known - ie N, S, E, W etc. before processing\n", + "\"\"\"\n", + "\n", + "dir_data_path = '/path/to/your/data/folder'\n", + "data = [dir_data_path + i for i in data_path]\n", + "\n", + "flat_path = '/path/to/your/flat.fits'\n", + "dark_path = '/path/to/your/dark.fits'\n", + "\n", + "input_dict = {\n", + "\n", + " #input data\n", + " 'data_f' : data, #hrt pipeline allows multiple files at once to be processed \n", + " 'flat_f' : flat_path,\n", + " 'dark_f' : dark_path,\n", + " \n", + " #input/output type + scaling\n", + " 'L1_input' : False, #ignore - in development\n", + " 'L1_8_generate': False, #ignore - in development\n", + " 'scale_data' : True, #leave as True if L1 data\n", + " 'accum_scaling' : True, #leave as True if L1 data\n", + " 'bit_conversion' : True, #leave as True if L1 data\n", + " \n", + " #reduction\n", + " 'dark_c' : True, #apply dark field correction\n", + " 'flat_c' : True, #apply flat field correction\n", + " 'norm_f' : True, #normalise the flats before used (DEFAULT: True)\n", + " 'clean_f' : True, #clean the flat fields with unsharp masking\n", + " 'sigma' : 59, #unsharp masking gaussian width\n", + " 'clean_mode' : \"V\", #options 'QUV', 'UV', 'V' for the unsharp masking\n", + " 'flat_states' : 24, #options 24 (DEFAULT), 4 (one each pol state), 6 (one each wavelength), \n", + " 'prefilter_f': None, #provide the path for the prefilter .fits file\n", + " 'fs_c' : True, #apply the field stop\n", + " 'limb' : None, #for limb images - must know what limb in FOV: 'N','E','W','S'\n", + " 'demod' : True, #demodulate to create the stokes maps\n", + " 'norm_stokes' : True, #normalise the stokes maps to I_continuum\n", + " 'ItoQUV' : False, #apply I-> Q,U,V cross talk correction\n", + " 'ghost_c' : False, #if True, excludes ghost region for ItoQUV ctalk calculation \n", + " 'rte' : False, #options: RTE', 'CE' (classical estimates), 'CE+RTE'\n", + " 'p_milos' : False, #DO NOT USE\n", + " 'cmilos_fits': False, #use cmilos with .fits IO - 16% speed up\n", + " \n", + " #output dir/filenames\n", + " 'out_dir' : None, #directory where you want the output files to go (string)\n", + " 'out_stokes_file' : False, #if True, will save the final stokes array to fits file(s)\n", + " 'out_stokes_filename' : None, #if specific required otherwise will default to standard convention\n", + " 'out_rte_filename' : None, #if specific required otherwise will default to standard convention\n", + " 'config' : True, #if True, saves a copy of the input file with runtime in the output folder\n", + " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", + "}\n", + "\n", + "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-------------------------------------------------------------- \u001b[92m\n", + "PHI HRT data reduction software \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + "L1_input param set to True - Assuming L1 science data\n", + " \n", + "-->>>>>>> Reading Data\n", + "Input contains 1 scan(s)\n", + "Dividing by number of accumulations: 20\n", + "Continuum position at wave: 0\n", + "This scan has been flipped in the Y axis to conform to orientation standards. \n", + " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", + "All the scan(s) have the same dimension\n", + "All the scan(s) have the same continuum wavelength position\n", + "All the scan(s) have the same PMP Temperature Set Point: 50\n", + "Data shape is (2048, 2048, 24, 1)\n", + "All the scan(s) have the same IMGDIRX keyword: YES\n", + "Data reshaped to: (2048, 2048, 4, 6, 1)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load science data time: 0.992 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Flats\n", + "Dividing by number of accumulations: 150\n", + "Flat field shape is (24, 2048, 2048)\n", + "(2048, 2048, 4, 6)\n", + "Continuum position at wave: 5\n", + "The continuum position of the flat field is at 5 index position\n", + "The flat field continuum position is not the same as the data, trying to correct.\n", + "Flat PMP Temperature Set Point: 50\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load flats time: 1.074 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Darks \n", + "Dividing by number of accumulations: 20\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load darks time: 0.095 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Subtracting dark field\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Dark Field correction time: 0.069 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Cleaning flats with Unsharp Masking\n", + "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", + "Unsharp Masking V\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Cleaning flat time: 18.218 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Flats\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Normalising flat time: 0.205 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Correcting Flatfield\n", + "Dividing by 24 flats, one for each image\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Flat Field correction time: 19.146 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No prefilter mode\n", + " \u001b[0m\n", + "-->>>>>>> Applying field stop\n", + "\u001b\u001b[0m\r" + ] + }, + { + "ename": "FileNotFoundError", + "evalue": "[Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mphihrt_pipe\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'./input_jsons/test_nb.json'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe.py\u001b[0m in \u001b[0;36mphihrt_pipe\u001b[0;34m(input_json_file)\u001b[0m\n\u001b[1;32m 509\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 510\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfs_c\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 511\u001b[0;31m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mapply_field_stop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcols\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheader_imgdirx_exists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimgdirx_flipped\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 512\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe_sub.py\u001b[0m in \u001b[0;36mapply_field_stop\u001b[0;34m(data, rows, cols, header_imgdirx_exists, imgdirx_flipped)\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0mstart_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 351\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 352\u001b[0;31m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload_fits\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../field_stop/HRT_field_stop.fits'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 353\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload_fits\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../field_stop/HRT_field_stop_ghost.fits'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 354\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/utils.py\u001b[0m in \u001b[0;36mload_fits\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 36\u001b[0m \"\"\"\n\u001b[1;32m 37\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 38\u001b[0;31m \u001b[0mhdul_tmp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfits\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{path}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhdul_tmp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfitsopen\u001b[0;34m(name, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m return HDUList.fromfile(name, mode, memmap, save_backup, cache,\n\u001b[0;32m--> 165\u001b[0;31m lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfromfile\u001b[0;34m(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 403\u001b[0m return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,\n\u001b[1;32m 404\u001b[0m \u001b[0msave_backup\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msave_backup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 405\u001b[0;31m lazy_load_hdus=lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 406\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36m_readfrom\u001b[0;34m(cls, fileobj, data, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 1052\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[0;31m# instantiate a FITS file object (ffo)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1054\u001b[0;31m \u001b[0mfileobj\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemmap\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmemmap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1055\u001b[0m \u001b[0;31m# The Astropy mode is determined by the _File initializer if the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1056\u001b[0m \u001b[0;31m# supplied mode was None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/utils/decorators.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 533\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 534\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 535\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 536\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, fileobj, mode, memmap, overwrite, cache)\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_fileobj\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 192\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 193\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 194\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filelike\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m_open_filename\u001b[0;34m(self, filename, mode, overwrite)\u001b[0m\n\u001b[1;32m 572\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 573\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_try_read_compressed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmagic\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mext\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 574\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfileobj_open\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIO_FITS_MODES\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 575\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose_on_error\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/util.py\u001b[0m in \u001b[0;36mfileobj_open\u001b[0;34m(filename, mode)\u001b[0m\n\u001b[1;32m 394\u001b[0m \"\"\"\n\u001b[1;32m 395\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbuffering\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'" + ] + } + ], + "source": [ + "#RUN the pipe\n", + "\n", + "import sys\n", + "sys.path.insert(1, './src/')\n", + "from hrt_pipe import phihrt_pipe\n", + "\n", + "#change name of print for out_intermediate\n", + "#error with input file\n", + "\n", + "phihrt_pipe('./input_jsons/test_nb.json')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hrt_pipeline_env", + "language": "python", + "name": "hrt_pipeline_env" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/README.md b/README.md index 25a93f8..eb45d3c 100755 --- a/README.md +++ b/README.md @@ -26,9 +26,12 @@ Reduction software for SO/PHI-HRT instrument on the ESA Solar Orbiter Operating System Required: Linux +############################################################## + If running on bob MPS server and you have access +### RUN bash script - setup.sh - to skip the first 4 steps +############################################################## -Run bash script - setup.sh - to skip the first 3 steps OTHERWISE: @@ -63,6 +66,18 @@ conda env create -f environment.yml ```bash source activate hrt_pipeline_env ``` +############################################################## +### OPTIONAL - LOAD JUPYTER NOTEBOOK `hrt_pipeline_notebook.ipynb` WHICH HAS ALL THE FOLLOWING STEPS + +(once environment loaded and activated - need the environment to start and use all the steps in the notebook) + +First let jupyter notebook know the environment exists: + +``` +python -m ipykernel install --user --name hrt_pipeline_env +``` +Now start the notebook +############################################################## 5. Download files - see **DOWNLOAD INPUT FILES** Section @@ -111,7 +126,7 @@ Instructions: PHIDATAPASSWORD = ``` 5. Set the target download folder in the `download_from_db.py` file - 6. Run the file (will require dotenv python module to be installed - included in `dataproc`) + 6. Run the file (will require dotenv python module to be installed - included in `hrt_pipeline_env`) OR : use `download_files.py` to download images from the attic repository: https://www2.mps.mpg.de/services/proton/phi/fm/attic/ ## **OUTPUT** diff --git a/example_input_json.py b/example_input_json.py index 6279074..4bd5aa0 100644 --- a/example_input_json.py +++ b/example_input_json.py @@ -36,20 +36,23 @@ input_dict = { 'flat_states' : 24, #options 4 (one each pol state), 6 (one each wavelength), 24 'prefilter_f': None, 'fs_c' : True, - 'limb' : 'W', # for limb images - must know what limb in FOV: 'N','E','W','S' + 'limb' : None, # for limb images - must know what limb in FOV: 'N','E','W','S' 'demod' : True, 'norm_stokes' : True, 'ItoQUV' : False, #missing VtoQU - not developed yet + 'ghost_c' : True, 'ctalk_params' : None, #VtoQU parameters will be required in this argument once ready 'rte' : False, #options: ''RTE', 'CE', 'CE+RTE' 'p_milos' : False, #attempted, ran into problems - on hold - 'cmilos_fits_opt': False, #use cmilos with .fits IO - 16% speed up + 'cmilos_fits': False, #use cmilos with .fits IO - 16% speed up #output dir/filenames 'out_dir' : './', 'out_stokes_file' : False, #if True, will save stokes array to fits, the array that is fed into the RTE inversions 'out_stokes_filename' : None, #if specific and not default name 'out_rte_filename' : None, #if specific and not default name + 'config': True, + 'out_intermediate': False, } json.dump(input_dict, open(f"./input_jsons/nov_2020_L1.txt", "w")) diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb new file mode 100644 index 0000000..28d04b9 --- /dev/null +++ b/hrt_pipeline_notebook.ipynb @@ -0,0 +1,297 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# **PHI-HRT Pipeline**\n", + "\n", + "_____________\n", + "\n", + "Author: Jonas Sinjan (MPS)
\n", + "Contributor: Daniele Calchetti (MPS)\n", + "\n", + "Reductions Steps\n", + "\n", + "1. read in science data (+scaling) open path option + open for several scans at once\n", + "2. read in flat field (+scaling)- accepts only one flat field fits file\n", + "3. read in dark field (+scaling)\n", + "4. apply dark field (to only science - assumes flat is dark fielded)\n", + "5. option to clean flat field with unsharp masking (Stokes QUV, UV or V)\n", + "6. normalise flat field\n", + "7. apply flat field\n", + "8. prefilter correction\n", + "9. apply field stop\n", + "10. demodulate with const demod matrix\n", + "11. normalise to quiet sun\n", + "12. I -> Q,U,V cross talk correction\n", + "13. rte inversion with cmilos\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Download files\n", + "\n", + "(This requires the hrt_pipeline_env environment - or the correct modules installed with pip (see `requirements.txt`)\n", + "\n", + "Options:\n", + "\n", + "1. Can download manually yourself from the PHI Image Database: https://www2.mps.mpg.de/services/proton/phi/imgdb/\n", + "\n", + " Suggested filters on the database for HRT science data: \n", + " - KEYWORD DETECTOR = 'HRT'
\n", + " - Filename\\* like \\*L1_phi-hrt-ilam_date\\*\n", + " \n", + " Once you find the file you want use the Command Line: \n", + " \n", + " ```\n", + " wget --user yourusername --password yourpassword file_web_address_from_database\n", + " gunzip file.gz\n", + " ```\n", + " \n", + "2. Use the provided script in 'downloads' folder (**Benefit: can download multiple files at once**): `downloads/download_from_db.py`\n", + "\n", + " Instructions:\n", + " 1. From the database find the files you wish to download\n", + " 2. Copy the 'Download File List' that the database will generate\n", + " 3. Paste into the `downloads/file_names.txt` file\n", + " 4. Create a `downloads/.env` file with your MPS Windows login:
\n", + " ```text=\n", + " USER_NAME =\n", + " PHIDATAPASSWORD =\n", + " ``` \n", + " 5. Set the **target download folder** in the `download_from_db.py` file\n", + " 6. Run the file (will require dotenv python module to be installed - included in `hrt_pipeline_env`):\n", + " ```text=\n", + " python download_from_db.py\n", + " ```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Create Input JSON (config) file" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "#example\n", + "\n", + "data_path = ['data_one.fits', 'data_two.fits', 'etc.fits...'] \n", + "\n", + "#can have as many files as you like, contintue the list\n", + "\n", + "\"\"\"\n", + "IMPORTANT\n", + "\n", + "- files will be procssed with the same flat, dark\n", + "- must have the same continuum position, pmp temp etc - checks will be run, and pipeline will exit if they fail\n", + "- if data is a limb image, the limb in the FOV must be known - ie N, S, E, W etc. before processing\n", + "\"\"\"\n", + "\n", + "dir_data_path = '/path/to/your/data/folder'\n", + "data = [dir_data_path + i for i in data_path]\n", + "\n", + "flat_path = '/path/to/your/flat.fits'\n", + "dark_path = '/path/to/your/dark.fits'\n", + "\n", + "input_dict = {\n", + "\n", + " #input data\n", + " 'data_f' : data, #hrt pipeline allows multiple files at once to be processed \n", + " 'flat_f' : flat_path,\n", + " 'dark_f' : dark_path,\n", + " \n", + " #input/output type + scaling\n", + " 'L1_input' : False, #ignore - in development\n", + " 'L1_8_generate': False, #ignore - in development\n", + " 'scale_data' : True, #leave as True if L1 data\n", + " 'accum_scaling' : True, #leave as True if L1 data\n", + " 'bit_conversion' : True, #leave as True if L1 data\n", + " \n", + " #reduction\n", + " 'dark_c' : True, #apply dark field correction\n", + " 'flat_c' : True, #apply flat field correction\n", + " 'norm_f' : True, #normalise the flats before used (DEFAULT: True)\n", + " 'clean_f' : True, #clean the flat fields with unsharp masking\n", + " 'sigma' : 59, #unsharp masking gaussian width\n", + " 'clean_mode' : \"V\", #options 'QUV', 'UV', 'V' for the unsharp masking\n", + " 'flat_states' : 24, #options 24 (DEFAULT), 4 (one each pol state), 6 (one each wavelength), \n", + " 'prefilter_f': None, #provide the path for the prefilter .fits file\n", + " 'fs_c' : True, #apply the field stop\n", + " 'limb' : None, #for limb images - must know what limb in FOV: 'N','E','W','S'\n", + " 'demod' : True, #demodulate to create the stokes maps\n", + " 'norm_stokes' : True, #normalise the stokes maps to I_continuum\n", + " 'ItoQUV' : False, #apply I-> Q,U,V cross talk correction\n", + " 'ghost_c' : False, #if True, excludes ghost region for ItoQUV ctalk calculation \n", + " 'rte' : False, #options: RTE', 'CE' (classical estimates), 'CE+RTE'\n", + " 'p_milos' : False, #DO NOT USE\n", + " 'cmilos_fits': False, #use cmilos with .fits IO - 16% speed up\n", + " \n", + " #output dir/filenames\n", + " 'out_dir' : None, #directory where you want the output files to go (string)\n", + " 'out_stokes_file' : False, #if True, will save the final stokes array to fits file(s)\n", + " 'out_stokes_filename' : None, #if specific required otherwise will default to standard convention\n", + " 'out_rte_filename' : None, #if specific required otherwise will default to standard convention\n", + " 'config' : True, #if True, saves a copy of the input file with runtime in the output folder\n", + " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", + "}\n", + "\n", + "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-------------------------------------------------------------- \u001b[92m\n", + "PHI HRT data reduction software \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + "L1_input param set to True - Assuming L1 science data\n", + " \n", + "-->>>>>>> Reading Data\n", + "Input contains 1 scan(s)\n", + "Dividing by number of accumulations: 20\n", + "Continuum position at wave: 0\n", + "This scan has been flipped in the Y axis to conform to orientation standards. \n", + " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", + "All the scan(s) have the same dimension\n", + "All the scan(s) have the same continuum wavelength position\n", + "All the scan(s) have the same PMP Temperature Set Point: 50\n", + "Data shape is (2048, 2048, 24, 1)\n", + "All the scan(s) have the same IMGDIRX keyword: YES\n", + "Data reshaped to: (2048, 2048, 4, 6, 1)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load science data time: 0.596 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Flats\n", + "Dividing by number of accumulations: 150\n", + "Flat field shape is (24, 2048, 2048)\n", + "(2048, 2048, 4, 6)\n", + "Continuum position at wave: 5\n", + "The continuum position of the flat field is at 5 index position\n", + "The flat field continuum position is not the same as the data, trying to correct.\n", + "Flat PMP Temperature Set Point: 50\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load flats time: 0.629 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Darks \n", + "Dividing by number of accumulations: 20\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load darks time: 0.033 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Subtracting dark field\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Dark Field correction time: 0.072 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Cleaning flats with Unsharp Masking\n", + "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", + "Unsharp Masking V\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Cleaning flat time: 17.795 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Flats\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Normalising flat time: 0.207 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Correcting Flatfield\n", + "Dividing by 24 flats, one for each image\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Flat Field correction time: 18.728 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No prefilter mode\n", + " \u001b[0m\n", + "-->>>>>>> Applying field stop\n", + "\u001b\u001b[0m\r" + ] + }, + { + "ename": "FileNotFoundError", + "evalue": "[Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;31m#error with input file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mphihrt_pipe\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'./input_jsons/test_nb.json'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe.py\u001b[0m in \u001b[0;36mphihrt_pipe\u001b[0;34m(input_json_file)\u001b[0m\n\u001b[1;32m 509\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 510\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfs_c\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 511\u001b[0;31m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mapply_field_stop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcols\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheader_imgdirx_exists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimgdirx_flipped\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 512\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe_sub.py\u001b[0m in \u001b[0;36mapply_field_stop\u001b[0;34m(data, rows, cols, header_imgdirx_exists, imgdirx_flipped)\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0mstart_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 351\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 352\u001b[0;31m \u001b[0mfield_stop_loc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrealpath\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m__file__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 353\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 354\u001b[0m \u001b[0mfield_stop_loc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfield_stop_loc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'src/'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m'field_stop/'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/utils.py\u001b[0m in \u001b[0;36mload_fits\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 36\u001b[0m \"\"\"\n\u001b[1;32m 37\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 38\u001b[0;31m \u001b[0mhdul_tmp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfits\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{path}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhdul_tmp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfitsopen\u001b[0;34m(name, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m return HDUList.fromfile(name, mode, memmap, save_backup, cache,\n\u001b[0;32m--> 165\u001b[0;31m lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfromfile\u001b[0;34m(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 403\u001b[0m return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,\n\u001b[1;32m 404\u001b[0m \u001b[0msave_backup\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msave_backup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 405\u001b[0;31m lazy_load_hdus=lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 406\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36m_readfrom\u001b[0;34m(cls, fileobj, data, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 1052\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[0;31m# instantiate a FITS file object (ffo)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1054\u001b[0;31m \u001b[0mfileobj\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemmap\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmemmap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1055\u001b[0m \u001b[0;31m# The Astropy mode is determined by the _File initializer if the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1056\u001b[0m \u001b[0;31m# supplied mode was None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/utils/decorators.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 533\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 534\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 535\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 536\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, fileobj, mode, memmap, overwrite, cache)\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_fileobj\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 192\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 193\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 194\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filelike\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m_open_filename\u001b[0;34m(self, filename, mode, overwrite)\u001b[0m\n\u001b[1;32m 572\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 573\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_try_read_compressed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmagic\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mext\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 574\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfileobj_open\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIO_FITS_MODES\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 575\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose_on_error\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/util.py\u001b[0m in \u001b[0;36mfileobj_open\u001b[0;34m(filename, mode)\u001b[0m\n\u001b[1;32m 394\u001b[0m \"\"\"\n\u001b[1;32m 395\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbuffering\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'" + ] + } + ], + "source": [ + "#RUN the pipe\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import sys\n", + "sys.path.insert(1, './src/')\n", + "from hrt_pipe import phihrt_pipe\n", + "\n", + "#error with input file\n", + "\n", + "phihrt_pipe('./input_jsons/test_nb.json')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hrt_pipeline_env", + "language": "python", + "name": "hrt_pipeline_env" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/setup.sh b/setup.sh index 71a52d5..1b2649c 100644 --- a/setup.sh +++ b/setup.sh @@ -28,8 +28,8 @@ make cd .. -conda env create -f environment.yml +#conda env create -f environment.yml #pip install -r requrements.txt -#source activate hrt_pipeline_env +source activate hrt_pipeline_env diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index da960fa..f4cabbb 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -153,7 +153,7 @@ def phihrt_pipe(input_json_file): rte = input_dict['rte'] p_milos = input_dict['p_milos'] - cmilos_fits_opt = input_dict['cmilos_fits_opt'] + cmilos_fits_opt = input_dict['cmilos_fits'] out_dir = input_dict['out_dir'] out_stokes_file = input_dict['out_stokes_file'] @@ -172,7 +172,7 @@ def phihrt_pipe(input_json_file): overall_time = time.time() if L1_input: - print("L1_input param set to True - Assuming L1 science data") + #print("L1_input param set to True - Assuming L1 science data") accum_scaling = True bit_conversion = True scale_data = True @@ -708,7 +708,7 @@ def phihrt_pipe(input_json_file): if out_stokes_file: print(" ") - printc('Saving demodulated data to one _reduced.fits file per scan') + printc('Saving demodulated data to one _stokes.fits file per scan') if out_stokes_filename is not None: @@ -719,7 +719,7 @@ def phihrt_pipe(input_json_file): scan_name_list = out_stokes_filename scan_name_defined = True else: - print("Input demod filenames do not match the number of input arrays, reverting to default naming") + print("Input stokes filenames do not match the number of input arrays, reverting to default naming") scan_name_defined = False else: scan_name_defined = False @@ -731,38 +731,38 @@ def phihrt_pipe(input_json_file): for count, scan in enumerate(data_f): with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_reduced.fits") + print(f"Writing out stokes file as: {scan_name_list[count]}_reduced.fits") hdu_list[0].data = data[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_reduced.fits', overwrite=True) + hdu_list.writeto(out_dir + scan_name_list[count] + '_stokes.fits', overwrite=True) # DC change 20211014 if out_intermediate: # DC 20211116 if dark_c: # DC 20211116 with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_dark_corrected.fits") + print(f"Writing intermediate file as: {scan_name_list[count]}_dark_corrected.fits") hdu_list[0].data = data_darkc[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_dark_corrected.fits', overwrite=True) if flat_c: # DC 20211116 with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") + print(f"Writing intermediate file as: {scan_name_list[count]}_flat_corrected.fits") hdu_list[0].data = data_flatc[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) if prefilter_f is not None: # DC 20211116 with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") + print(f"Writing intermediate file as: {scan_name_list[count]}_prefilter_corrected.fits") hdu_list[0].data = data_PFc[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_prefilter_corrected.fits', overwrite=True) if demod: # DC 20211116 with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_demodulated.fits") + print(f"Writing intermediate file as: {scan_name_list[count]}_demodulated.fits") hdu_list[0].data = data_demod[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 252f1a3..66f024e 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -348,9 +348,13 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) start_time = time.time() - - field_stop,_ = load_fits('../field_stop/HRT_field_stop.fits') - field_stop_ghost,_ = load_fits('../field_stop/HRT_field_stop_ghost.fits') + + field_stop_loc = os.path.realpath(__file__) + + field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' + + field_stop,_ = load_fits(field_stop_loc + 'HRT_field_stop.fits') + field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') field_stop = np.where(field_stop > 0,1,0) field_stop_ghost = np.where(field_stop_ghost > 0,1,0) -- GitLab From 0e42b9b9e5baf9e48b762b1cf77822853ae6b61d Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:24:23 +0100 Subject: [PATCH 17/34] fs_ghost separate function --- hrt_pipeline_notebook.ipynb | 57 ++++++------------------------------- src/hrt_pipe.py | 7 +++-- src/hrt_pipe_sub.py | 39 ++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index 28d04b9..43cf783 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -152,7 +152,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "scrolled": false }, @@ -161,11 +161,12 @@ "name": "stdout", "output_type": "stream", "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n", "-------------------------------------------------------------- \u001b[92m\n", "PHI HRT data reduction software \u001b[92m\n", "-------------------------------------------------------------- \u001b[92m\n", - "L1_input param set to True - Assuming L1 science data\n", - " \n", + " \u001b[0m\n", "-->>>>>>> Reading Data\n", "Input contains 1 scan(s)\n", "Dividing by number of accumulations: 20\n", @@ -179,7 +180,7 @@ "All the scan(s) have the same IMGDIRX keyword: YES\n", "Data reshaped to: (2048, 2048, 4, 6, 1)\n", "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load science data time: 0.596 seconds \u001b[92m\n", + "------------ Load science data time: 0.597 seconds \u001b[92m\n", "-------------------------------------------------------------- \u001b[92m\n", " \u001b[0m\n", "-->>>>>>> Reading Flats\n", @@ -191,63 +192,23 @@ "The flat field continuum position is not the same as the data, trying to correct.\n", "Flat PMP Temperature Set Point: 50\n", "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load flats time: 0.629 seconds \u001b[92m\n", + "------------ Load flats time: 0.625 seconds \u001b[92m\n", "-------------------------------------------------------------- \u001b[92m\n", " \u001b[0m\n", "-->>>>>>> Reading Darks \n", "Dividing by number of accumulations: 20\n", "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load darks time: 0.033 seconds \u001b[92m\n", + "------------ Load darks time: 0.031 seconds \u001b[92m\n", "-------------------------------------------------------------- \u001b[92m\n", " \u001b[0m\n", "-->>>>>>> Subtracting dark field\n", "-------------------------------------------------------------- \u001b[92m\n", - "------------- Dark Field correction time: 0.072 seconds \u001b[92m\n", + "------------- Dark Field correction time: 0.067 seconds \u001b[92m\n", "-------------------------------------------------------------- \u001b[92m\n", " \u001b[0m\n", "-->>>>>>> Cleaning flats with Unsharp Masking\n", "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", - "Unsharp Masking V\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Cleaning flat time: 17.795 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Normalising Flats\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Normalising flat time: 0.207 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Correcting Flatfield\n", - "Dividing by 24 flats, one for each image\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Flat Field correction time: 18.728 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> No prefilter mode\n", - " \u001b[0m\n", - "-->>>>>>> Applying field stop\n", - "\u001b\u001b[0m\r" - ] - }, - { - "ename": "FileNotFoundError", - "evalue": "[Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;31m#error with input file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mphihrt_pipe\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'./input_jsons/test_nb.json'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe.py\u001b[0m in \u001b[0;36mphihrt_pipe\u001b[0;34m(input_json_file)\u001b[0m\n\u001b[1;32m 509\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 510\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfs_c\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 511\u001b[0;31m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mapply_field_stop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcols\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheader_imgdirx_exists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimgdirx_flipped\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 512\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe_sub.py\u001b[0m in \u001b[0;36mapply_field_stop\u001b[0;34m(data, rows, cols, header_imgdirx_exists, imgdirx_flipped)\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0mstart_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 351\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 352\u001b[0;31m \u001b[0mfield_stop_loc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrealpath\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m__file__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 353\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 354\u001b[0m \u001b[0mfield_stop_loc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfield_stop_loc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'src/'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m'field_stop/'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/utils.py\u001b[0m in \u001b[0;36mload_fits\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 36\u001b[0m \"\"\"\n\u001b[1;32m 37\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 38\u001b[0;31m \u001b[0mhdul_tmp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfits\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{path}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhdul_tmp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfitsopen\u001b[0;34m(name, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m return HDUList.fromfile(name, mode, memmap, save_backup, cache,\n\u001b[0;32m--> 165\u001b[0;31m lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfromfile\u001b[0;34m(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 403\u001b[0m return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,\n\u001b[1;32m 404\u001b[0m \u001b[0msave_backup\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msave_backup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 405\u001b[0;31m lazy_load_hdus=lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 406\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36m_readfrom\u001b[0;34m(cls, fileobj, data, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 1052\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[0;31m# instantiate a FITS file object (ffo)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1054\u001b[0;31m \u001b[0mfileobj\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemmap\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmemmap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1055\u001b[0m \u001b[0;31m# The Astropy mode is determined by the _File initializer if the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1056\u001b[0m \u001b[0;31m# supplied mode was None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/utils/decorators.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 533\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 534\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 535\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 536\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, fileobj, mode, memmap, overwrite, cache)\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_fileobj\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 192\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 193\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 194\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filelike\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m_open_filename\u001b[0;34m(self, filename, mode, overwrite)\u001b[0m\n\u001b[1;32m 572\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 573\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_try_read_compressed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmagic\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mext\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 574\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfileobj_open\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIO_FITS_MODES\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 575\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose_on_error\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/util.py\u001b[0m in \u001b[0;36mfileobj_open\u001b[0;34m(filename, mode)\u001b[0m\n\u001b[1;32m 394\u001b[0m \"\"\"\n\u001b[1;32m 395\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbuffering\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'" + "Unsharp Masking V\n" ] } ], diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index f4cabbb..7414598 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -508,7 +508,10 @@ def phihrt_pipe(input_json_file): #----------------- if fs_c: - data, field_stop, field_stop_ghost = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) + data, field_stop = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) + + if ghost_c: + field_stop_ghost = load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) else: @@ -617,8 +620,6 @@ def phihrt_pipe(input_json_file): start_time = time.time() - num_of_scans = data_shape[-1] - slope, offset = 0, 1 q, u, v = 0, 1, 2 CTparams = np.zeros((2,3,number_of_scans)) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 66f024e..ce141ce 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -354,23 +354,54 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' field_stop,_ = load_fits(field_stop_loc + 'HRT_field_stop.fits') - field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') + if ghost_c: + field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') field_stop = np.where(field_stop > 0,1,0) - field_stop_ghost = np.where(field_stop_ghost > 0,1,0) + if ghost_c: + field_stop_ghost = np.where(field_stop_ghost > 0,1,0) if header_imgdirx_exists: if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction - field_stop_ghost = field_stop_ghost[:,::-1] + if ghost_c: + field_stop_ghost = field_stop_ghost[:,::-1] data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) + if ghost_c: + return data, field_stop, field_stop_ghost + else: + return data, field_stop + + +def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: + """ + apply field stop ghost mask to the science data + """ + print(" ") + printc("-->>>>>>> Loading ghost field stop",color=bcolors.OKGREEN) + + start_time = time.time() + + field_stop_loc = os.path.realpath(__file__) + field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' + + field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') + field_stop_ghost = np.where(field_stop_ghost > 0,1,0) + + if header_imgdirx_exists: + if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software + field_stop_ghost = field_stop_ghost[:,::-1] + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Load Ghost Field Stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + return field_stop_ghost - return data, field_stop, field_stop_ghost def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): import random, statistics -- GitLab From 592126c5f7bb4e4232ead6a5e205826cc1b09a6a Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:32:44 +0100 Subject: [PATCH 18/34] rm incorrect ghost_c --- .gitignore | 1 + hrt_pipeline_notebook.ipynb | 74 ++++++++----------------------------- src/hrt_pipe_sub.py | 14 ++----- 3 files changed, 20 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index ad930d5..9328fc4 100755 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ src/create_input_json.py *.pyc input_jsons/sep_2021_L1_west.json input_jsons/sep_2021_L1_south_noflat.json +.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index 43cf783..88cee90 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -156,64 +156,9 @@ "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n", - "-------------------------------------------------------------- \u001b[92m\n", - "PHI HRT data reduction software \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Data\n", - "Input contains 1 scan(s)\n", - "Dividing by number of accumulations: 20\n", - "Continuum position at wave: 0\n", - "This scan has been flipped in the Y axis to conform to orientation standards. \n", - " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", - "All the scan(s) have the same dimension\n", - "All the scan(s) have the same continuum wavelength position\n", - "All the scan(s) have the same PMP Temperature Set Point: 50\n", - "Data shape is (2048, 2048, 24, 1)\n", - "All the scan(s) have the same IMGDIRX keyword: YES\n", - "Data reshaped to: (2048, 2048, 4, 6, 1)\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load science data time: 0.597 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Flats\n", - "Dividing by number of accumulations: 150\n", - "Flat field shape is (24, 2048, 2048)\n", - "(2048, 2048, 4, 6)\n", - "Continuum position at wave: 5\n", - "The continuum position of the flat field is at 5 index position\n", - "The flat field continuum position is not the same as the data, trying to correct.\n", - "Flat PMP Temperature Set Point: 50\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load flats time: 0.625 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Darks \n", - "Dividing by number of accumulations: 20\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load darks time: 0.031 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Subtracting dark field\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Dark Field correction time: 0.067 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Cleaning flats with Unsharp Masking\n", - "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", - "Unsharp Masking V\n" - ] - } - ], + "outputs": [], "source": [ - "#RUN the pipe\n", + "#Example RUN the pipe\n", "%load_ext autoreload\n", "%autoreload 2\n", "\n", @@ -231,7 +176,20 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "#The better way is to run:\n", + "import os\n", + "cwd = os.getcwd()\n", + "os.chdir(cwd + './src/')\n", + "\n", + "###############################################\n", + "# CHANGE INPUT FILE LOC IN 'phihrt_pipe'\n", + "###############################################\n", + "\n", + "!python run.py\n", + "\n", + "os.chdir(cwd)" + ] } ], "metadata": { diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index ce141ce..b3ef4f4 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -354,28 +354,20 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' field_stop,_ = load_fits(field_stop_loc + 'HRT_field_stop.fits') - if ghost_c: - field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') field_stop = np.where(field_stop > 0,1,0) - if ghost_c: - field_stop_ghost = np.where(field_stop_ghost > 0,1,0) if header_imgdirx_exists: if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction - if ghost_c: - field_stop_ghost = field_stop_ghost[:,::-1] - data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] + data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) - if ghost_c: - return data, field_stop, field_stop_ghost - else: - return data, field_stop + + return data, field_stop def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: -- GitLab From 1c0119294690bf322f6c9a1db310c5ecb67e2ffd Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:33:33 +0100 Subject: [PATCH 19/34] notebook update --- hrt_pipeline_notebook.ipynb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index 88cee90..ea9e9f3 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -150,6 +150,13 @@ "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Run the Pip" + ] + }, { "cell_type": "code", "execution_count": null, -- GitLab From 43467d55b75ff9b479bd0f7175af16065fe3b402 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:35:18 +0100 Subject: [PATCH 20/34] typo --- hrt_pipeline_notebook.ipynb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index ea9e9f3..5b2f28e 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -147,14 +147,22 @@ " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", "}\n", "\n", - "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" + "####################################\n", + "# CHANGE NAME OF FILE\n", + "####################################\n", + "\n", + "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run - " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Step 3: Run the Pip" + "# Step 3: Run the Pipeline\n", + "\n", + "Two options\n", + "1. Run within notebook
\n", + "2. Run in Terminal" ] }, { @@ -173,9 +181,9 @@ "sys.path.insert(1, './src/')\n", "from hrt_pipe import phihrt_pipe\n", "\n", - "#error with input file\n", + "#insert name of your input file\n", "\n", - "phihrt_pipe('./input_jsons/test_nb.json')" + "phihrt_pipe('./input_jsons/your_input_file.json')" ] }, { -- GitLab From a8afd9b3fd2f20f2fc3f75d422f0805858376c24 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 19 Nov 2021 17:37:05 +0100 Subject: [PATCH 21/34] upd --- hrt_pipeline_notebook.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index 5b2f28e..e4f0338 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -151,7 +151,7 @@ "# CHANGE NAME OF FILE\n", "####################################\n", "\n", - "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run - " + "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" ] }, { -- GitLab From e3c1ea26a85094853d85a262686bc24c399027b3 Mon Sep 17 00:00:00 2001 From: "sinjan@mps.mpg.de" Date: Mon, 22 Nov 2021 14:04:56 +0100 Subject: [PATCH 22/34] update comments --- .../hrt_pipeline_notebook-checkpoint.ipynb | 137 +++++------------- 1 file changed, 36 insertions(+), 101 deletions(-) diff --git a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb index dda12f2..e4f0338 100644 --- a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb +++ b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb @@ -147,121 +147,43 @@ " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", "}\n", "\n", + "####################################\n", + "# CHANGE NAME OF FILE\n", + "####################################\n", + "\n", "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Run the Pipeline\n", + "\n", + "Two options\n", + "1. Run within notebook
\n", + "2. Run in Terminal" + ] + }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "scrolled": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-------------------------------------------------------------- \u001b[92m\n", - "PHI HRT data reduction software \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - "L1_input param set to True - Assuming L1 science data\n", - " \n", - "-->>>>>>> Reading Data\n", - "Input contains 1 scan(s)\n", - "Dividing by number of accumulations: 20\n", - "Continuum position at wave: 0\n", - "This scan has been flipped in the Y axis to conform to orientation standards. \n", - " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", - "All the scan(s) have the same dimension\n", - "All the scan(s) have the same continuum wavelength position\n", - "All the scan(s) have the same PMP Temperature Set Point: 50\n", - "Data shape is (2048, 2048, 24, 1)\n", - "All the scan(s) have the same IMGDIRX keyword: YES\n", - "Data reshaped to: (2048, 2048, 4, 6, 1)\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load science data time: 0.992 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Flats\n", - "Dividing by number of accumulations: 150\n", - "Flat field shape is (24, 2048, 2048)\n", - "(2048, 2048, 4, 6)\n", - "Continuum position at wave: 5\n", - "The continuum position of the flat field is at 5 index position\n", - "The flat field continuum position is not the same as the data, trying to correct.\n", - "Flat PMP Temperature Set Point: 50\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load flats time: 1.074 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Darks \n", - "Dividing by number of accumulations: 20\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load darks time: 0.095 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Subtracting dark field\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Dark Field correction time: 0.069 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Cleaning flats with Unsharp Masking\n", - "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", - "Unsharp Masking V\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Cleaning flat time: 18.218 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Normalising Flats\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Normalising flat time: 0.205 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Correcting Flatfield\n", - "Dividing by 24 flats, one for each image\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Flat Field correction time: 19.146 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> No prefilter mode\n", - " \u001b[0m\n", - "-->>>>>>> Applying field stop\n", - "\u001b\u001b[0m\r" - ] - }, - { - "ename": "FileNotFoundError", - "evalue": "[Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mphihrt_pipe\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'./input_jsons/test_nb.json'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe.py\u001b[0m in \u001b[0;36mphihrt_pipe\u001b[0;34m(input_json_file)\u001b[0m\n\u001b[1;32m 509\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 510\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfs_c\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 511\u001b[0;31m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mapply_field_stop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcols\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheader_imgdirx_exists\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mimgdirx_flipped\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 512\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/hrt_pipe_sub.py\u001b[0m in \u001b[0;36mapply_field_stop\u001b[0;34m(data, rows, cols, header_imgdirx_exists, imgdirx_flipped)\u001b[0m\n\u001b[1;32m 350\u001b[0m \u001b[0mstart_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 351\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 352\u001b[0;31m \u001b[0mfield_stop\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload_fits\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../field_stop/HRT_field_stop.fits'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 353\u001b[0m \u001b[0mfield_stop_ghost\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0m_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload_fits\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../field_stop/HRT_field_stop_ghost.fits'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 354\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/src/utils.py\u001b[0m in \u001b[0;36mload_fits\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 36\u001b[0m \"\"\"\n\u001b[1;32m 37\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 38\u001b[0;31m \u001b[0mhdul_tmp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfits\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{path}'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 39\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 40\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhdul_tmp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfitsopen\u001b[0;34m(name, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 164\u001b[0m return HDUList.fromfile(name, mode, memmap, save_backup, cache,\n\u001b[0;32m--> 165\u001b[0;31m lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 166\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 167\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36mfromfile\u001b[0;34m(cls, fileobj, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 403\u001b[0m return cls._readfrom(fileobj=fileobj, mode=mode, memmap=memmap,\n\u001b[1;32m 404\u001b[0m \u001b[0msave_backup\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msave_backup\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 405\u001b[0;31m lazy_load_hdus=lazy_load_hdus, **kwargs)\n\u001b[0m\u001b[1;32m 406\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/hdu/hdulist.py\u001b[0m in \u001b[0;36m_readfrom\u001b[0;34m(cls, fileobj, data, mode, memmap, save_backup, cache, lazy_load_hdus, **kwargs)\u001b[0m\n\u001b[1;32m 1052\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1053\u001b[0m \u001b[0;31m# instantiate a FITS file object (ffo)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1054\u001b[0;31m \u001b[0mfileobj\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_File\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmemmap\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmemmap\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcache\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcache\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1055\u001b[0m \u001b[0;31m# The Astropy mode is determined by the _File initializer if the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1056\u001b[0m \u001b[0;31m# supplied mode was None\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/utils/decorators.py\u001b[0m in \u001b[0;36mwrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 533\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 534\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 535\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 536\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 537\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, fileobj, mode, memmap, overwrite, cache)\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_fileobj\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 192\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 193\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filename\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 194\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_open_filelike\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfileobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moverwrite\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/file.py\u001b[0m in \u001b[0;36m_open_filename\u001b[0;34m(self, filename, mode, overwrite)\u001b[0m\n\u001b[1;32m 572\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 573\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_try_read_compressed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmagic\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mext\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mext\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 574\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfileobj_open\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mIO_FITS_MODES\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 575\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose_on_error\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/.conda/envs/hrt_pipeline_env/lib/python3.6/site-packages/astropy/io/fits/util.py\u001b[0m in \u001b[0;36mfileobj_open\u001b[0;34m(filename, mode)\u001b[0m\n\u001b[1;32m 394\u001b[0m \"\"\"\n\u001b[1;32m 395\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 396\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbuffering\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '../field_stop/HRT_field_stop.fits'" - ] - } - ], + "outputs": [], "source": [ - "#RUN the pipe\n", + "#Example RUN the pipe\n", + "%load_ext autoreload\n", + "%autoreload 2\n", "\n", "import sys\n", "sys.path.insert(1, './src/')\n", "from hrt_pipe import phihrt_pipe\n", "\n", - "#change name of print for out_intermediate\n", - "#error with input file\n", + "#insert name of your input file\n", "\n", - "phihrt_pipe('./input_jsons/test_nb.json')" + "phihrt_pipe('./input_jsons/your_input_file.json')" ] }, { @@ -269,7 +191,20 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "#The better way is to run:\n", + "import os\n", + "cwd = os.getcwd()\n", + "os.chdir(cwd + './src/')\n", + "\n", + "###############################################\n", + "# CHANGE INPUT FILE LOC IN 'phihrt_pipe'\n", + "###############################################\n", + "\n", + "!python run.py\n", + "\n", + "os.chdir(cwd)" + ] } ], "metadata": { -- GitLab From 06a3b157d1be024a0da70f5052ddc98f31a59463 Mon Sep 17 00:00:00 2001 From: "sinjan@mps.mpg.de" Date: Mon, 22 Nov 2021 14:13:52 +0100 Subject: [PATCH 23/34] mv inversion functions to separate file + update test jsons with new entries --- src/hrt_pipe.py | 5 +- src/{hrt_pipe_sub.py => inversions.py} | 531 ------------------------ src/processes.py | 534 +++++++++++++++++++++++++ test/test_jsons/test_1.json | 2 +- test/test_jsons/test_2.json | 2 +- test/test_jsons/test_3.json | 2 +- test/test_jsons/test_4.json | 2 +- test/test_jsons/test_5.json | 2 +- test/test_jsons/test_8.json | 2 +- test/test_settings.py | 4 + 10 files changed, 546 insertions(+), 540 deletions(-) rename src/{hrt_pipe_sub.py => inversions.py} (54%) create mode 100644 src/processes.py diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 7414598..bc584a6 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -2,7 +2,6 @@ from posix import listdir import numpy as np import os.path from astropy.io import fits -# from scipy.ndimage import gaussian_filter import time import datetime from operator import itemgetter @@ -11,8 +10,8 @@ import matplotlib.pyplot as plt from numpy.core.numeric import True_ from utils import * -from hrt_pipe_sub import * - +from processes import * +from inversions import * def phihrt_pipe(input_json_file): diff --git a/src/hrt_pipe_sub.py b/src/inversions.py similarity index 54% rename from src/hrt_pipe_sub.py rename to src/inversions.py index b3ef4f4..7ae6e30 100644 --- a/src/hrt_pipe_sub.py +++ b/src/inversions.py @@ -1,541 +1,10 @@ import numpy as np from astropy.io import fits -from scipy.ndimage import gaussian_filter -from operator import itemgetter from utils import * import os import time import subprocess -def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_exists, imgdirx_flipped, cpos_arr) -> np.ndarray: - """ - load, scale, flip and correct flat - """ - print(" ") - printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) - - start_time = time.time() - - # flat from IP-5 - if '0024151020000' in flat_f or '0024150020000' in flat_f: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=False) - else: - flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, - scale_data=scale_data) - - if 'IMGDIRX' in header_flat: - header_fltdirx_exists = True - fltdirx_flipped = str(header_flat['IMGDIRX']) - else: - header_fltdirx_exists = False - fltdirx_flipped = 'NO' - - print(f"Flat field shape is {flat.shape}") - # correction based on science data - see if flat and science are both flipped or not - flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) - - flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] - flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states - flat = np.moveaxis(flat, 2,-1) - - print(flat.shape) - - _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position - - print(f"The continuum position of the flat field is at {cpos_f} index position") - - #-------- - # test if the science and flat have continuum at same position - #-------- - - flat = compare_cpos(flat,cpos_f,cpos_arr[0]) - - flat_pmp_temp = str(header_flat['HPMPTSP1']) - - print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") - - #-------- - # correct for missing line in particular flat field - #-------- - - if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' - print("This flat has a missing line - filling in with neighbouring pixels") - flat_copy = flat.copy() - flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) - - del flat_copy - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return flat - - -def load_dark(dark_f) -> np.ndarray: - """ - loads dark field from given path - """ - print(" ") - printc('-->>>>>>> Reading Darks',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - dark,_ = get_data(dark_f) - - dark_shape = dark.shape - - if dark_shape != (2048,2048): - - if dark.ndim > 2: - printc("Dark Field Input File has more dimensions than the expected 2048,2048 format: {}",dark_f,color=bcolors.WARNING) - raise ValueError - - printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) - printc("Attempting to correct ",color=bcolors.WARNING) - - - try: - if dark_shape[0] > 2048: - dark = dark[dark_shape[0]-2048:,:] - - except Exception: - printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) - raise ValueError - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return dark - - except Exception: - printc("ERROR, Unable to open and process darks file: {}",dark_f,color=bcolors.FAIL) - - -def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: - """ - subtracts dark field from flat field and science data - """ - print(" ") - print("-->>>>>>> Subtracting dark field") - - start_time = time.time() - - data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] - #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Dark Field correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data, flat - - -def normalise_flat(flat, flat_f, ceny, cenx) -> np.ndarray: - """ - normalise flat fields at each wavelength position to remove the spectral line - """ - print(" ") - printc('-->>>>>>> Normalising Flats',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - norm_fac = np.mean(flat[ceny,cenx, :, :], axis = (0,1))[np.newaxis, np.newaxis, ...] #mean of the central 1k x 1k - flat /= norm_fac - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Normalising flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return flat - - except Exception: - printc("ERROR, Unable to normalise the flat fields: {}",flat_f,color=bcolors.FAIL) - - -def demod_hrt(data,pmp_temp, verbose = True) -> np.ndarray: - ''' - Use constant demodulation matrices to demodulate input data - ''' - if pmp_temp == '50': - demod_data = np.array([[ 0.28037298, 0.18741922, 0.25307596, 0.28119895], - [ 0.40408596, 0.10412157, -0.7225681, 0.20825675], - [-0.19126636, -0.5348939, 0.08181918, 0.64422774], - [-0.56897295, 0.58620095, -0.2579202, 0.2414017 ]]) - - elif pmp_temp == '40': - demod_data = np.array([[ 0.26450154, 0.2839626, 0.12642948, 0.3216773 ], - [ 0.59873885, 0.11278069, -0.74991184, 0.03091451], - [ 0.10833212, -0.5317737, -0.1677862, 0.5923593 ], - [-0.46916953, 0.47738808, -0.43824592, 0.42579797]]) - - else: - printc("Demodulation Matrix for PMP TEMP of {pmp_temp} deg is not available", color = bcolors.FAIL) - if verbose: - printc(f'Using a constant demodulation matrix for a PMP TEMP of {pmp_temp} deg',color = bcolors.OKGREEN) - - demod_data = demod_data.reshape((4,4)) - shape = data.shape - demod = np.tile(demod_data, (shape[0],shape[1],1,1)) - - if data.ndim == 5: - #if data array has more than one scan - data = np.moveaxis(data,-1,0) #moving number of scans to first dimension - - data = np.matmul(demod,data) - data = np.moveaxis(data,0,-1) #move scans back to the end - - elif data.ndim == 4: - #for if data has just one scan - data = np.matmul(demod,data) - - return data, demod - - -def unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode,clean_f,pol_end=4,verbose=True): - """ - unsharp masks the flat fields to blur our polarimetric structures due to solar rotation - clean_f = ['blurring', 'fft'] - """ - flat_demod, demodM = demod_hrt(flat, flat_pmp_temp,verbose) - - norm_factor = np.mean(flat_demod[512:1536,512:1536,0,cpos_arr[0]]) - - flat_demod /= norm_factor - - new_demod_flats = np.copy(flat_demod) - -# b_arr = np.zeros((2048,2048,3,5)) - - if cpos_arr[0] == 0: - wv_range = range(1,6) - - elif cpos_arr[0] == 5: - wv_range = range(5) - - if clean_mode == "QUV": - start_clean_pol = 1 - if verbose: - print("Unsharp Masking Q,U,V") - - elif clean_mode == "UV": - start_clean_pol = 2 - if verbose: - print("Unsharp Masking U,V") - - elif clean_mode == "V": - start_clean_pol = 3 - if verbose: - print("Unsharp Masking V") - - if clean_f == 'blurring': - blur = lambda a: gaussian_filter(a,sigma) - elif clean_f == 'fft': - x = np.fft.fftfreq(2048,1) - fftgaus2d = np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[:,np.newaxis] * np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[np.newaxis] - blur = lambda a : (np.fft.ifftn(fftgaus2d*np.fft.fftn(a.copy()))).real - - for pol in range(start_clean_pol,pol_end): - - for wv in wv_range: #not the continuum - - a = np.copy(np.clip(flat_demod[:,:,pol,wv], -0.02, 0.02)) - b = a - blur(a) -# b_arr[:,:,pol-1,wv-1] = b - c = a - b - - new_demod_flats[:,:,pol,wv] = c - - invM = np.linalg.inv(demodM) - - return np.matmul(invM, new_demod_flats*norm_factor) - - -def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: - """ - correct science data with flat fields - """ - print(" ") - printc('-->>>>>>> Correcting Flatfield',color=bcolors.OKGREEN) - - start_time = time.time() - - try: - if flat_states == 6: - - printc("Dividing by 6 flats, one for each wavelength",color=bcolors.OKGREEN) - - tmp = np.mean(flat,axis=-2) #avg over pol states for the wavelength - - return data / tmp[rows,cols, np.newaxis, :, np.newaxis] - - - elif flat_states == 24: - - printc("Dividing by 24 flats, one for each image",color=bcolors.OKGREEN) - - return data / flat[rows,cols, :, :, np.newaxis] #only one new axis for the scans - - elif flat_states == 4: - - printc("Dividing by 4 flats, one for each pol state",color=bcolors.OKGREEN) - - tmp = np.mean(flat,axis=-1) #avg over wavelength - - return data / tmp[rows,cols, :, np.newaxis, np.newaxis] - else: - print(" ") - printc('-->>>>>>> Unable to apply flat correction. Please insert valid flat_states',color=bcolors.WARNING) - - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data - - except: - printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) - - - -def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): - """ - applies prefilter correction - adapted from SPGPylibs - """ - def _get_v1_index1(x): - index1, v1 = min(enumerate([abs(i) for i in x]), key=itemgetter(1)) - return v1, index1 - - data_shape = data.shape - - for scan in range(data_shape[-1]): - - voltage_list = voltagesData_arr[scan] - - for wv in range(6): - - v = voltage_list[wv] - - vdif = [v - pf for pf in prefilter_voltages] - - v1, index1 = _get_v1_index1(vdif) - - if vdif[index1] >= 0: - v2 = vdif[index1 + 1] - index2 = index1 + 1 - - else: - v2 = vdif[index1-1] - index2 = index1 - 1 - - imprefilter = (prefilter[:,:, index1]*v1 + prefilter[:,:, index2]*v2)/(v1+v2) #interpolation between nearest voltages - - data[:,:,:,wv,scan] /= imprefilter[...,np.newaxis] - - return data - -def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: - """ - apply field stop mask to the science data - """ - print(" ") - printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) - - start_time = time.time() - - field_stop_loc = os.path.realpath(__file__) - - field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' - - field_stop,_ = load_fits(field_stop_loc + 'HRT_field_stop.fits') - - field_stop = np.where(field_stop > 0,1,0) - - if header_imgdirx_exists: - if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software - field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction - - - data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - - return data, field_stop - - -def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: - """ - apply field stop ghost mask to the science data - """ - print(" ") - printc("-->>>>>>> Loading ghost field stop",color=bcolors.OKGREEN) - - start_time = time.time() - - field_stop_loc = os.path.realpath(__file__) - field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' - - field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') - field_stop_ghost = np.where(field_stop_ghost > 0,1,0) - - if header_imgdirx_exists: - if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software - field_stop_ghost = field_stop_ghost[:,::-1] - - printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Load Ghost Field Stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) - printc('--------------------------------------------------------------',bcolors.OKGREEN) - return field_stop_ghost - - -def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): - import random, statistics - from scipy.optimize import curve_fit - def linear(x,a,b): - return a*x + b - my = [] - sy = [] - - x = data_demod[roi>0,0,cpos].flatten() - ids = np.logical_and(x > limit, x < 1.5) - x = x[ids].flatten() - - N = x.size - idx = random.sample(range(N),npoints) - mx = x[idx].mean() - sx = x[idx].std() - xp = np.linspace(x.min(), x.max(), 100) - - A = np.vstack([x, np.ones(len(x))]).T - - # I to Q - yQ = data_demod[roi>0,1,wl].flatten() - yQ = yQ[ids].flatten() - my.append(yQ[idx].mean()) - sy.append(yQ[idx].std()) - cQ = curve_fit(linear,x,yQ,p0=[0,0])[0] - pQ = np.poly1d(cQ) - - # I to U - yU = data_demod[roi>0,2,wl].flatten() - yU = yU[ids].flatten() - my.append(yU[idx].mean()) - sy.append(yU[idx].std()) - cU = curve_fit(linear,x,yU,p0=[0,0])[0] - pU = np.poly1d(cU) - - # I to V - yV = data_demod[roi>0,3,wl].flatten() - yV = yV[ids].flatten() - my.append(yV[idx].mean()) - sy.append(yV[idx].std()) - cV = curve_fit(linear,x,yV,p0=[0,0])[0] - pV = np.poly1d(cV) - - if verbose: - - PLT_RNG = 3 - fig, ax = plt.subplots(figsize=(8, 8)) - ax.scatter(x[idx],yQ[idx],color='red',alpha=0.6,s=10) - ax.plot(xp, pQ(xp), color='red', linestyle='dashed',linewidth=3.0) - - ax.scatter(x[idx],yU[idx],color='blue',alpha=0.6,s=10) - ax.plot(xp, pU(xp), color='blue', linestyle='dashed',linewidth=3.0) - - ax.scatter(x[idx],yV[idx],color='green',alpha=0.6,s=10) - ax.plot(xp, pV(xp), color='green', linestyle='dashed',linewidth=3.0) - - ax.set_xlim([mx - PLT_RNG * sx,mx + PLT_RNG * sx]) - ax.set_ylim([min(my) - 1.8*PLT_RNG * statistics.mean(sy),max(my) + PLT_RNG * statistics.mean(sy)]) - ax.set_xlabel('Stokes I') - ax.set_ylabel('Stokes Q/U/V') - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.4*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4), style='italic',bbox={'facecolor': 'red', 'alpha': 0.1, 'pad': 1}, fontsize=15) - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.55*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4), style='italic',bbox={'facecolor': 'blue', 'alpha': 0.1, 'pad': 1}, fontsize=15) - ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.7*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4), style='italic',bbox={'facecolor': 'green', 'alpha': 0.1, 'pad': 1}, fontsize=15) -# fig.show() - - print('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4)) - print('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4)) - print('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4)) - -# return cQ,cU,cV, (idx,x,xp,yQ,yU,yV,pQ,pU,pV,mx,sx,my,sy) - else: - printc('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4),color=bcolors.OKGREEN) - printc('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4),color=bcolors.OKGREEN) - printc('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4),color=bcolors.OKGREEN) - ct = np.asarray((cQ,cU,cV)).T - return ct - -def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): - """ - performs cross talk correction for I -> Q,U,V - """ - before_ctalk_data = np.copy(data) - data_shape = data.shape - -# ceny = slice(data_shape[0]//2 - data_shape[0]//4, data_shape[0]//2 + data_shape[0]//4) -# cenx = slice(data_shape[1]//2 - data_shape[1]//4, data_shape[1]//2 + data_shape[1]//4) - - cont_stokes = np.ones(data_shape[-1]) - - for scan in range(data_shape[-1]): - cont_stokes[scan] = np.mean(data[Ic_mask[...,scan],0,cpos_arr[0],scan]) - - for i in range(6): - -# stokes_i_wv_avg = np.mean(data[ceny,cenx,0,i,:], axis = (0,1)) - stokes_i_wv_avg = np.ones(data_shape[-1]) - for scan in range(data_shape[-1]): - stokes_i_wv_avg[scan] = np.mean(data[Ic_mask[...,scan],0,i,scan]) - - if norm_stokes: - #if normed, applies normalised offset to normed stokes - - tmp_param = ctalk_params*np.divide(stokes_i_wv_avg,cont_stokes) - - q_slope = tmp_param[0,0,:] - u_slope = tmp_param[0,1,:] - v_slope = tmp_param[0,2,:] - - q_int = tmp_param[1,0,:] - u_int = tmp_param[1,1,:] - v_int = tmp_param[1,2,:] - - data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int - - data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int - - data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int - - else: - #if not normed, applies raw offset cross talk correction to raw stokes counts - - tmp_param = ctalk_params[0,:,:]*np.divide(stokes_i_wv_avg,cont_stokes) - - q_slope = tmp_param[0,:] - u_slope = tmp_param[1,:] - v_slope = tmp_param[2,:] - - q_int = ctalk_params[1,0,:] - u_int = ctalk_params[1,1,:] - v_int = ctalk_params[1,2,:] - - data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int*stokes_i_wv_avg - - data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int*stokes_i_wv_avg - - data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int*stokes_i_wv_avg - - return data - - def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): """ RTE inversion using CMILOS diff --git a/src/processes.py b/src/processes.py new file mode 100644 index 0000000..9e54c52 --- /dev/null +++ b/src/processes.py @@ -0,0 +1,534 @@ +import numpy as np +from scipy.ndimage import gaussian_filter +from operator import itemgetter +from utils import * +import os +import time + +def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_exists, imgdirx_flipped, cpos_arr) -> np.ndarray: + """ + load, scale, flip and correct flat + """ + print(" ") + printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) + + start_time = time.time() + + # flat from IP-5 + if '0024151020000' in flat_f or '0024150020000' in flat_f: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=False) + else: + flat, header_flat = get_data(flat_f, scaling = accum_scaling, bit_convert_scale=bit_conversion, + scale_data=scale_data) + + if 'IMGDIRX' in header_flat: + header_fltdirx_exists = True + fltdirx_flipped = str(header_flat['IMGDIRX']) + else: + header_fltdirx_exists = False + fltdirx_flipped = 'NO' + + print(f"Flat field shape is {flat.shape}") + # correction based on science data - see if flat and science are both flipped or not + flat = compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped) + + flat = np.moveaxis(flat, 0,-1) #so that it is [y,x,24] + flat = flat.reshape(2048,2048,6,4) #separate 24 images, into 6 wavelengths, with each 4 pol states + flat = np.moveaxis(flat, 2,-1) + + print(flat.shape) + + _, _, _, cpos_f = fits_get_sampling(flat_f,verbose = True) #get flat continuum position + + print(f"The continuum position of the flat field is at {cpos_f} index position") + + #-------- + # test if the science and flat have continuum at same position + #-------- + + flat = compare_cpos(flat,cpos_f,cpos_arr[0]) + + flat_pmp_temp = str(header_flat['HPMPTSP1']) + + print(f"Flat PMP Temperature Set Point: {flat_pmp_temp}") + + #-------- + # correct for missing line in particular flat field + #-------- + + if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' + print("This flat has a missing line - filling in with neighbouring pixels") + flat_copy = flat.copy() + flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) + + del flat_copy + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return flat + + +def load_dark(dark_f) -> np.ndarray: + """ + loads dark field from given path + """ + print(" ") + printc('-->>>>>>> Reading Darks',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + dark,_ = get_data(dark_f) + + dark_shape = dark.shape + + if dark_shape != (2048,2048): + + if dark.ndim > 2: + printc("Dark Field Input File has more dimensions than the expected 2048,2048 format: {}",dark_f,color=bcolors.WARNING) + raise ValueError + + printc("Dark Field Input File not in 2048,2048 format: {}",dark_f,color=bcolors.WARNING) + printc("Attempting to correct ",color=bcolors.WARNING) + + + try: + if dark_shape[0] > 2048: + dark = dark[dark_shape[0]-2048:,:] + + except Exception: + printc("ERROR, Unable to correct shape of dark field data: {}",dark_f,color=bcolors.FAIL) + raise ValueError + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return dark + + except Exception: + printc("ERROR, Unable to open and process darks file: {}",dark_f,color=bcolors.FAIL) + + +def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: + """ + subtracts dark field from flat field and science data + """ + print(" ") + print("-->>>>>>> Subtracting dark field") + + start_time = time.time() + + data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] + #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Dark Field correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data, flat + + +def normalise_flat(flat, flat_f, ceny, cenx) -> np.ndarray: + """ + normalise flat fields at each wavelength position to remove the spectral line + """ + print(" ") + printc('-->>>>>>> Normalising Flats',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + norm_fac = np.mean(flat[ceny,cenx, :, :], axis = (0,1))[np.newaxis, np.newaxis, ...] #mean of the central 1k x 1k + flat /= norm_fac + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Normalising flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return flat + + except Exception: + printc("ERROR, Unable to normalise the flat fields: {}",flat_f,color=bcolors.FAIL) + + +def demod_hrt(data,pmp_temp, verbose = True) -> np.ndarray: + ''' + Use constant demodulation matrices to demodulate input data + ''' + if pmp_temp == '50': + demod_data = np.array([[ 0.28037298, 0.18741922, 0.25307596, 0.28119895], + [ 0.40408596, 0.10412157, -0.7225681, 0.20825675], + [-0.19126636, -0.5348939, 0.08181918, 0.64422774], + [-0.56897295, 0.58620095, -0.2579202, 0.2414017 ]]) + + elif pmp_temp == '40': + demod_data = np.array([[ 0.26450154, 0.2839626, 0.12642948, 0.3216773 ], + [ 0.59873885, 0.11278069, -0.74991184, 0.03091451], + [ 0.10833212, -0.5317737, -0.1677862, 0.5923593 ], + [-0.46916953, 0.47738808, -0.43824592, 0.42579797]]) + + else: + printc("Demodulation Matrix for PMP TEMP of {pmp_temp} deg is not available", color = bcolors.FAIL) + if verbose: + printc(f'Using a constant demodulation matrix for a PMP TEMP of {pmp_temp} deg',color = bcolors.OKGREEN) + + demod_data = demod_data.reshape((4,4)) + shape = data.shape + demod = np.tile(demod_data, (shape[0],shape[1],1,1)) + + if data.ndim == 5: + #if data array has more than one scan + data = np.moveaxis(data,-1,0) #moving number of scans to first dimension + + data = np.matmul(demod,data) + data = np.moveaxis(data,0,-1) #move scans back to the end + + elif data.ndim == 4: + #for if data has just one scan + data = np.matmul(demod,data) + + return data, demod + + +def unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode,clean_f,pol_end=4,verbose=True): + """ + unsharp masks the flat fields to blur our polarimetric structures due to solar rotation + clean_f = ['blurring', 'fft'] + """ + flat_demod, demodM = demod_hrt(flat, flat_pmp_temp,verbose) + + norm_factor = np.mean(flat_demod[512:1536,512:1536,0,cpos_arr[0]]) + + flat_demod /= norm_factor + + new_demod_flats = np.copy(flat_demod) + +# b_arr = np.zeros((2048,2048,3,5)) + + if cpos_arr[0] == 0: + wv_range = range(1,6) + + elif cpos_arr[0] == 5: + wv_range = range(5) + + if clean_mode == "QUV": + start_clean_pol = 1 + if verbose: + print("Unsharp Masking Q,U,V") + + elif clean_mode == "UV": + start_clean_pol = 2 + if verbose: + print("Unsharp Masking U,V") + + elif clean_mode == "V": + start_clean_pol = 3 + if verbose: + print("Unsharp Masking V") + + if clean_f == 'blurring': + blur = lambda a: gaussian_filter(a,sigma) + elif clean_f == 'fft': + x = np.fft.fftfreq(2048,1) + fftgaus2d = np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[:,np.newaxis] * np.exp(-2*np.pi**2*(x-0)**2*sigma**2)[np.newaxis] + blur = lambda a : (np.fft.ifftn(fftgaus2d*np.fft.fftn(a.copy()))).real + + for pol in range(start_clean_pol,pol_end): + + for wv in wv_range: #not the continuum + + a = np.copy(np.clip(flat_demod[:,:,pol,wv], -0.02, 0.02)) + b = a - blur(a) +# b_arr[:,:,pol-1,wv-1] = b + c = a - b + + new_demod_flats[:,:,pol,wv] = c + + invM = np.linalg.inv(demodM) + + return np.matmul(invM, new_demod_flats*norm_factor) + + +def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: + """ + correct science data with flat fields + """ + print(" ") + printc('-->>>>>>> Correcting Flatfield',color=bcolors.OKGREEN) + + start_time = time.time() + + try: + if flat_states == 6: + + printc("Dividing by 6 flats, one for each wavelength",color=bcolors.OKGREEN) + + tmp = np.mean(flat,axis=-2) #avg over pol states for the wavelength + + return data / tmp[rows,cols, np.newaxis, :, np.newaxis] + + + elif flat_states == 24: + + printc("Dividing by 24 flats, one for each image",color=bcolors.OKGREEN) + + return data / flat[rows,cols, :, :, np.newaxis] #only one new axis for the scans + + elif flat_states == 4: + + printc("Dividing by 4 flats, one for each pol state",color=bcolors.OKGREEN) + + tmp = np.mean(flat,axis=-1) #avg over wavelength + + return data / tmp[rows,cols, :, np.newaxis, np.newaxis] + else: + print(" ") + printc('-->>>>>>> Unable to apply flat correction. Please insert valid flat_states',color=bcolors.WARNING) + + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data + + except: + printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) + + + +def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): + """ + applies prefilter correction + adapted from SPGPylibs + """ + def _get_v1_index1(x): + index1, v1 = min(enumerate([abs(i) for i in x]), key=itemgetter(1)) + return v1, index1 + + data_shape = data.shape + + for scan in range(data_shape[-1]): + + voltage_list = voltagesData_arr[scan] + + for wv in range(6): + + v = voltage_list[wv] + + vdif = [v - pf for pf in prefilter_voltages] + + v1, index1 = _get_v1_index1(vdif) + + if vdif[index1] >= 0: + v2 = vdif[index1 + 1] + index2 = index1 + 1 + + else: + v2 = vdif[index1-1] + index2 = index1 - 1 + + imprefilter = (prefilter[:,:, index1]*v1 + prefilter[:,:, index2]*v2)/(v1+v2) #interpolation between nearest voltages + + data[:,:,:,wv,scan] /= imprefilter[...,np.newaxis] + + return data + +def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: + """ + apply field stop mask to the science data + """ + print(" ") + printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) + + start_time = time.time() + + field_stop_loc = os.path.realpath(__file__) + + field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' + + field_stop,_ = load_fits(field_stop_loc + 'HRT_field_stop.fits') + + field_stop = np.where(field_stop > 0,1,0) + + if header_imgdirx_exists: + if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software + field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction + + + data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + + return data, field_stop + + +def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: + """ + apply field stop ghost mask to the science data + """ + print(" ") + printc("-->>>>>>> Loading ghost field stop",color=bcolors.OKGREEN) + + start_time = time.time() + + field_stop_loc = os.path.realpath(__file__) + field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' + + field_stop_ghost,_ = load_fits(field_stop_loc + 'HRT_field_stop_ghost.fits') + field_stop_ghost = np.where(field_stop_ghost > 0,1,0) + + if header_imgdirx_exists: + if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software + field_stop_ghost = field_stop_ghost[:,::-1] + + printc('--------------------------------------------------------------',bcolors.OKGREEN) + printc(f"------------- Load Ghost Field Stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc('--------------------------------------------------------------',bcolors.OKGREEN) + return field_stop_ghost + + +def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): + import random, statistics + from scipy.optimize import curve_fit + def linear(x,a,b): + return a*x + b + my = [] + sy = [] + + x = data_demod[roi>0,0,cpos].flatten() + ids = np.logical_and(x > limit, x < 1.5) + x = x[ids].flatten() + + N = x.size + idx = random.sample(range(N),npoints) + mx = x[idx].mean() + sx = x[idx].std() + xp = np.linspace(x.min(), x.max(), 100) + + A = np.vstack([x, np.ones(len(x))]).T + + # I to Q + yQ = data_demod[roi>0,1,wl].flatten() + yQ = yQ[ids].flatten() + my.append(yQ[idx].mean()) + sy.append(yQ[idx].std()) + cQ = curve_fit(linear,x,yQ,p0=[0,0])[0] + pQ = np.poly1d(cQ) + + # I to U + yU = data_demod[roi>0,2,wl].flatten() + yU = yU[ids].flatten() + my.append(yU[idx].mean()) + sy.append(yU[idx].std()) + cU = curve_fit(linear,x,yU,p0=[0,0])[0] + pU = np.poly1d(cU) + + # I to V + yV = data_demod[roi>0,3,wl].flatten() + yV = yV[ids].flatten() + my.append(yV[idx].mean()) + sy.append(yV[idx].std()) + cV = curve_fit(linear,x,yV,p0=[0,0])[0] + pV = np.poly1d(cV) + + if verbose: + + PLT_RNG = 3 + fig, ax = plt.subplots(figsize=(8, 8)) + ax.scatter(x[idx],yQ[idx],color='red',alpha=0.6,s=10) + ax.plot(xp, pQ(xp), color='red', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yU[idx],color='blue',alpha=0.6,s=10) + ax.plot(xp, pU(xp), color='blue', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yV[idx],color='green',alpha=0.6,s=10) + ax.plot(xp, pV(xp), color='green', linestyle='dashed',linewidth=3.0) + + ax.set_xlim([mx - PLT_RNG * sx,mx + PLT_RNG * sx]) + ax.set_ylim([min(my) - 1.8*PLT_RNG * statistics.mean(sy),max(my) + PLT_RNG * statistics.mean(sy)]) + ax.set_xlabel('Stokes I') + ax.set_ylabel('Stokes Q/U/V') + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.4*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4), style='italic',bbox={'facecolor': 'red', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.55*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4), style='italic',bbox={'facecolor': 'blue', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.7*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4), style='italic',bbox={'facecolor': 'green', 'alpha': 0.1, 'pad': 1}, fontsize=15) +# fig.show() + + print('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4)) + print('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4)) + print('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4)) + +# return cQ,cU,cV, (idx,x,xp,yQ,yU,yV,pQ,pU,pV,mx,sx,my,sy) + else: + printc('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4),color=bcolors.OKGREEN) + printc('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4),color=bcolors.OKGREEN) + printc('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4),color=bcolors.OKGREEN) + ct = np.asarray((cQ,cU,cV)).T + return ct + +def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): + """ + performs cross talk correction for I -> Q,U,V + """ + before_ctalk_data = np.copy(data) + data_shape = data.shape + +# ceny = slice(data_shape[0]//2 - data_shape[0]//4, data_shape[0]//2 + data_shape[0]//4) +# cenx = slice(data_shape[1]//2 - data_shape[1]//4, data_shape[1]//2 + data_shape[1]//4) + + cont_stokes = np.ones(data_shape[-1]) + + for scan in range(data_shape[-1]): + cont_stokes[scan] = np.mean(data[Ic_mask[...,scan],0,cpos_arr[0],scan]) + + for i in range(6): + +# stokes_i_wv_avg = np.mean(data[ceny,cenx,0,i,:], axis = (0,1)) + stokes_i_wv_avg = np.ones(data_shape[-1]) + for scan in range(data_shape[-1]): + stokes_i_wv_avg[scan] = np.mean(data[Ic_mask[...,scan],0,i,scan]) + + if norm_stokes: + #if normed, applies normalised offset to normed stokes + + tmp_param = ctalk_params*np.divide(stokes_i_wv_avg,cont_stokes) + + q_slope = tmp_param[0,0,:] + u_slope = tmp_param[0,1,:] + v_slope = tmp_param[0,2,:] + + q_int = tmp_param[1,0,:] + u_int = tmp_param[1,1,:] + v_int = tmp_param[1,2,:] + + data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int + + data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int + + data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int + + else: + #if not normed, applies raw offset cross talk correction to raw stokes counts + + tmp_param = ctalk_params[0,:,:]*np.divide(stokes_i_wv_avg,cont_stokes) + + q_slope = tmp_param[0,:] + u_slope = tmp_param[1,:] + v_slope = tmp_param[2,:] + + q_int = ctalk_params[1,0,:] + u_int = ctalk_params[1,1,:] + v_int = ctalk_params[1,2,:] + + data[:,:,1,i,:] = before_ctalk_data[:,:,1,i,:] - before_ctalk_data[:,:,0,i,:]*q_slope - q_int*stokes_i_wv_avg + + data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int*stokes_i_wv_avg + + data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int*stokes_i_wv_avg + + return data \ No newline at end of file diff --git a/test/test_jsons/test_1.json b/test/test_jsons/test_1.json index 5938e93..c9e9d5d 100644 --- a/test/test_jsons/test_1.json +++ b/test/test_jsons/test_1.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "ghost_c": null, "out_intermediate": null, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file diff --git a/test/test_jsons/test_2.json b/test/test_jsons/test_2.json index 3924666..9c5c252 100644 --- a/test/test_jsons/test_2.json +++ b/test/test_jsons/test_2.json @@ -1 +1 @@ -{"data_f": [""], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config":false} \ No newline at end of file +{"data_f": [""], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "ghost_c": null, "out_intermediate": null, "fs_c": false, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config":false} \ No newline at end of file diff --git a/test/test_jsons/test_3.json b/test/test_jsons/test_3.json index 9067efe..2ddcee3 100644 --- a/test/test_jsons/test_3.json +++ b/test/test_jsons/test_3.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": true, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config":false} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": true, "L1_8_generate": true, "scale_data": false, "accum_scaling": false, "bit_conversion": true, "dark_c": false, "flat_c": true, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "ghost_c": null, "out_intermediate": null, "fs_c": false, "limb":"W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config":false} \ No newline at end of file diff --git a/test/test_jsons/test_4.json b/test/test_jsons/test_4.json index 0c520dd..c9fbc4d 100644 --- a/test/test_jsons/test_4.json +++ b/test/test_jsons/test_4.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": true, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "limb": "W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": true, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "ghost_c": null, "out_intermediate": null, "limb": "W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file diff --git a/test/test_jsons/test_5.json b/test/test_jsons/test_5.json index a806872..aa0b935 100644 --- a/test/test_jsons/test_5.json +++ b/test/test_jsons/test_5.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": true, "flat_c": true, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "limb": "W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": true, "flat_c": true, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "ghost_c": null, "out_intermediate": null, "limb": "W", "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file diff --git a/test/test_jsons/test_8.json b/test/test_jsons/test_8.json index 0463149..fd16981 100644 --- a/test/test_jsons/test_8.json +++ b/test/test_jsons/test_8.json @@ -1 +1 @@ -{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits_opt": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": false, "L1_8_generate": false, "scale_data": false, "accum_scaling": false, "bit_conversion": false, "dark_c": false, "flat_c": false, "norm_f": false, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 4, "prefilter_f": null, "fs_c": false, "ghost_c": null, "out_intermediate": null, "demod": false, "norm_stokes": false, "ItoQUV": false, "ctalk_params": null, "rte": null, "p_milos": false, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/sep_2021_cmilos/", "out_stokes_file": false, "out_stokes_filename": null, "out_rte_filename": null, "config": false} \ No newline at end of file diff --git a/test/test_settings.py b/test/test_settings.py index 00d724b..de613b7 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -6,8 +6,12 @@ import unittest import numpy as np import sys sys.path.append('../') +sys.path.append('../src/') from src.hrt_pipe import phihrt_pipe +from src.utils import * +from src.inversions import * +from src.processes import * def test_one(): #test with almost everything off after reading in all files -- GitLab From 0b3aaf8fb60610af4cb80ac18514a90b0ec26cd7 Mon Sep 17 00:00:00 2001 From: "sinjan@mps.mpg.de" Date: Mon, 22 Nov 2021 14:43:21 +0100 Subject: [PATCH 24/34] change the output filenames to match ESA convention --- src/hrt_pipe.py | 30 ++++----- src/inversions.py | 156 +++++++++++++++++++++++++++++----------------- 2 files changed, 115 insertions(+), 71 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index bc584a6..b8731a3 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -163,6 +163,11 @@ def phihrt_pipe(input_json_file): config = True else: config = input_dict['config'] + + if 'vers' not in input_dict: + vrs = '01' + else: + vrs = input_dict['vers'] except Exception as e: print(f"Missing key(s) in the input config file: {e}") @@ -708,8 +713,9 @@ def phihrt_pipe(input_json_file): if out_stokes_file: print(" ") - printc('Saving demodulated data to one _stokes.fits file per scan') + printc('Saving demodulated data to one \'stokes\' file per scan') + #check if user set specific output filenames, check for duplicates, otherwise use the DID if out_stokes_filename is not None: if isinstance(out_stokes_filename,str): @@ -724,17 +730,18 @@ def phihrt_pipe(input_json_file): else: scan_name_defined = False - if not scan_name_defined: #check if already defined by input, otherwise generate - scan_name_list = check_filenames(data_f) + if not scan_name_defined: #check if already defined by user + scan_name_list = check_filenames(data_f) #extract the DIDs and check no duplicates - for count, scan in enumerate(data_f): + stokes_file, _ = create_output_filenames(scan, scan_name_list[count], version = vrs) + with fits.open(scan) as hdu_list: print(f"Writing out stokes file as: {scan_name_list[count]}_reduced.fits") hdu_list[0].data = data[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_stokes.fits', overwrite=True) + hdu_list.writeto(out_dir + stokes_file, overwrite=True) # DC change 20211014 @@ -766,11 +773,6 @@ def phihrt_pipe(input_json_file): hdu_list[0].data = data_demod[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) - - - # with fits.open(scan) as hdu_list: - # hdu_list[0].data = limb_copy - # hdu_list.writeto(out_dir+scan_name_list[count]+'_limb_fit_input.fits', overwrite=True) else: print(" ") @@ -798,18 +800,18 @@ def phihrt_pipe(input_json_file): if p_milos: try: - pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) except ValueError: print("Running CMILOS instead!") - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) else: if cmilos_fits_opt: - cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) else: - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) else: print(" ") diff --git a/src/inversions.py b/src/inversions.py index 7ae6e30..ebd8eac 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -5,7 +5,26 @@ import os import time import subprocess -def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): +def create_output_filenames(filename, DID, version = '01'): + try: + L2_str = filename.replace('L1', 'L2') + versioned = L2_str.split('V')[0] + version + DID + '.fits' + stokes_file = versioned.replace('ilam', 'stokes') + icnt_file = versioned.replace('ilam', 'icnt') + bmag_file = versioned.replace('ilam', 'bmag') + bazi_file = versioned.replace('ilam', 'bazi') + binc_file = versioned.replace('ilam', 'binc') + blos_file = versioned.replace('ilam', 'blos') + vlos_file = versioned.replace('ilam', 'vlos') + + return stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file + + except Exception: + print("The input file: {file_path} does not contain 'L1'") + raise KeyError + + +def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -36,7 +55,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field file_path = data_f[scan] wave_axis = wve_axis_arr[scan] - hdr = hdr_arr[scan] + hdr_scan = hdr_arr[scan] #must invert each scan independently, as cmilos only takes in one dataset at a time @@ -156,6 +175,8 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) + stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) + else: if isinstance(out_rte_filename, list): filename_root = out_rte_filename[scan] @@ -167,47 +188,55 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field filename_root = str(file_path.split('.fits')[0][-10:]) print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root + + # with fits.open(file_path) as hdu_list: + # hdu_list[0].header = hdr_scan + # hdu_list[0].data = rte_data_products + # hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + #blos with fits.open(file_path) as hdu_list: - hdu_list[0].header= hdr + hdu_list[0].header= hdr_scan hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion + hdu_list.writeto(out_dir+blos_file, overwrite=True) + + #bazi with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bazi_file, overwrite=True) + #binc with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+binc_file, overwrite=True) + #bmag with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bmag_file, overwrite=True) + #vlos with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+vlos_file, overwrite=True) + #Icnt with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+icnt_file, overwrite=True) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- CMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) -def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): +def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -379,6 +408,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) + stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) else: if isinstance(out_rte_filename, list): filename_root = out_rte_filename[scan] @@ -390,40 +420,43 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, filename_root = str(file_path.split('.fits')[0][-10:]) print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root + #blos with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header= hdr_scan hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion + hdu_list.writeto(out_dir+blos_file, overwrite=True) + + #bazi with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bazi_file, overwrite=True) + #binc with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+binc_file, overwrite=True) + #bmag with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bmag_file, overwrite=True) + #vlos with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+vlos_file, overwrite=True) + #Icnt with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan # DC 20211117 + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+icnt_file, overwrite=True) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) @@ -431,7 +464,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, -def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir): +def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using PMILOS """ @@ -462,6 +495,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st file_path = data_f[scan] wave_axis = wve_axis_arr[scan] + hdr_scan = hdr_scan[scan] #must invert each scan independently, as cmilos only takes in one dataset at a time @@ -565,6 +599,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st rte_data_products = np.zeros((6,result.shape[0],result.shape[1])) rte_data_products[0,:,:] = result[:,:,7] + result[:,:,8] #continuum + rte_data_products[1,:,:] = result[:,:,1] #b mag strength rte_data_products[2,:,:] = result[:,:,5] #inclination rte_data_products[3,:,:] = result[:,:,6] #azimuth rte_data_products[4,:,:] = result[:,:,2] #vlos @@ -572,47 +607,54 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 - #flipping taken care of for the field stop in the hrt_pipe - #printc(f' ---- >>>>> and HERE now .... ',color=bcolors.WARNING) if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) + stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) else: filename_root = out_rte_filename - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root + # with fits.open(file_path) as hdu_list: + # hdu_list[0].header = hdr + # hdu_list[0].data = rte_data_products + # hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + + #blos with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header= hdr_scan hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) - # DC change 20211101 Gherdardo needs separate fits files from inversion + hdu_list.writeto(out_dir+blos_file, overwrite=True) + + #bazi with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bazi_file, overwrite=True) + #binc with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+binc_file, overwrite=True) + #bmag with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+bmag_file, overwrite=True) + #vlos with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+vlos_file, overwrite=True) + #Icnt with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) + hdu_list.writeto(out_dir+icnt_file, overwrite=True) printc('--------------------------------------------------------------',bcolors.OKGREEN) -- GitLab From eb993164891c8d92c53697ee659232c5e2fa87f3 Mon Sep 17 00:00:00 2001 From: "sinjan@mps.mpg.de" Date: Mon, 22 Nov 2021 15:14:35 +0100 Subject: [PATCH 25/34] output file name bug fixes --- src/hrt_pipe.py | 15 ++++++++------- src/inversions.py | 8 +++++--- test/test_jsons/test_6.json | 1 + 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index b8731a3..5cbc6af 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -168,6 +168,9 @@ def phihrt_pipe(input_json_file): vrs = '01' else: vrs = input_dict['vers'] + if len(vrs) != 2: + print(f"Desired Version 'vers' from the input file is not 2 characters long: {vrs}") + raise KeyError except Exception as e: print(f"Missing key(s) in the input config file: {e}") @@ -422,7 +425,7 @@ def phihrt_pipe(input_json_file): # OPTIONAL Unsharp Masking clean the flat field stokes Q, U or V images #----------------- - if clean_f is not None and flat_c: + if clean_f and flat_c: print(" ") printc('-->>>>>>> Cleaning flats with Unsharp Masking',color=bcolors.OKGREEN) @@ -735,10 +738,10 @@ def phihrt_pipe(input_json_file): for count, scan in enumerate(data_f): - stokes_file, _ = create_output_filenames(scan, scan_name_list[count], version = vrs) + stokes_file = create_output_filenames(scan, scan_name_list[count], version = vrs)[0] with fits.open(scan) as hdu_list: - print(f"Writing out stokes file as: {scan_name_list[count]}_reduced.fits") + print(f"Writing out stokes file as: {stokes_file}") hdu_list[0].data = data[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + stokes_file, overwrite=True) @@ -837,7 +840,5 @@ def phihrt_pipe(input_json_file): printc('--------------------------------------------------------------',color=bcolors.OKGREEN) - if flat_c: - return data, flat - else: - return data + + return data diff --git a/src/inversions.py b/src/inversions.py index ebd8eac..6efed5f 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -7,8 +7,10 @@ import subprocess def create_output_filenames(filename, DID, version = '01'): try: - L2_str = filename.replace('L1', 'L2') - versioned = L2_str.split('V')[0] + version + DID + '.fits' + file_start = filename.split('solo_')[1] + file_start = 'solo_' + file_start + L2_str = file_start.replace('L1', 'L2') + versioned = L2_str.split('V')[0] + 'V' + version + '_' + DID + '.fits' stokes_file = versioned.replace('ilam', 'stokes') icnt_file = versioned.replace('ilam', 'icnt') bmag_file = versioned.replace('ilam', 'bmag') @@ -495,7 +497,7 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field file_path = data_f[scan] wave_axis = wve_axis_arr[scan] - hdr_scan = hdr_scan[scan] + hdr_scan = hdr_arr[scan] #must invert each scan independently, as cmilos only takes in one dataset at a time diff --git a/test/test_jsons/test_6.json b/test/test_jsons/test_6.json index e69de29..e2df2bc 100644 --- a/test/test_jsons/test_6.json +++ b/test/test_jsons/test_6.json @@ -0,0 +1 @@ +{"data_f": ["/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits"], "flat_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210911T120504_V202110200555C_0169110100.fits", "dark_f": "/data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210428T130238_V202109240900C_0164281001.fits", "L1_input": false, "L1_8_generate": false, "scale_data": true, "accum_scaling": true, "bit_conversion": true, "dark_c": true, "flat_c": true, "norm_f": true, "clean_f": false, "sigma": 59, "clean_mode": "V", "flat_states": 24, "prefilter_f": null, "fs_c": true, "ghost_c": null, "out_intermediate": null, "limb":"W", "demod": true, "norm_stokes": true, "ItoQUV": true, "ctalk_params": null, "rte": "RTE", "p_milos": true, "cmilos_fits": false, "out_dir": "/data/slam/home/sinjan/hrt_pipe_results/tests/", "out_stokes_file": true, "out_stokes_filename": null, "out_rte_filename": null, "config": false, "vers": "02"} \ No newline at end of file -- GitLab From dff59766cc0115d86f615e61815cec452a182bb2 Mon Sep 17 00:00:00 2001 From: "sinjan@mps.mpg.de" Date: Mon, 22 Nov 2021 15:35:00 +0100 Subject: [PATCH 26/34] notebook update --- .../hrt_pipeline_notebook-checkpoint.ipynb | 149 ++++++++++++++++-- hrt_pipeline_notebook.ipynb | 149 ++++++++++++++++-- src/hrt_pipe.py | 2 +- 3 files changed, 275 insertions(+), 25 deletions(-) diff --git a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb index e4f0338..f74226c 100644 --- a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb +++ b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb @@ -79,7 +79,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -145,11 +145,21 @@ " 'out_rte_filename' : None, #if specific required otherwise will default to standard convention\n", " 'config' : True, #if True, saves a copy of the input file with runtime in the output folder\n", " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", - "}\n", + " 'vers': \"01\", #desired version number, only 2 characters 01 -> 99, if not specified, '01' default\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "##################################################################\n", + "\n", + "# CHANGE NAME OF CONFIG FILE + CREATE\n", "\n", - "####################################\n", - "# CHANGE NAME OF FILE\n", - "####################################\n", + "##################################################################\n", "\n", "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" ] @@ -167,11 +177,124 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n", + "-------------------------------------------------------------- \u001b[92m\n", + "PHI HRT data reduction software \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Data\n", + "Input contains 1 scan(s)\n", + "Dividing by number of accumulations: 20\n", + "Continuum position at wave: 0\n", + "This scan has been flipped in the Y axis to conform to orientation standards. \n", + " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", + "All the scan(s) have the same dimension\n", + "All the scan(s) have the same continuum wavelength position\n", + "All the scan(s) have the same PMP Temperature Set Point: 50\n", + "Data shape is (2048, 2048, 24, 1)\n", + "All the scan(s) have the same IMGDIRX keyword: YES\n", + "Data reshaped to: (2048, 2048, 4, 6, 1)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load science data time: 0.589 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Flats\n", + "Dividing by number of accumulations: 150\n", + "Flat field shape is (24, 2048, 2048)\n", + "(2048, 2048, 4, 6)\n", + "Continuum position at wave: 5\n", + "The continuum position of the flat field is at 5 index position\n", + "The flat field continuum position is not the same as the data, trying to correct.\n", + "Flat PMP Temperature Set Point: 50\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load flats time: 0.615 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Darks \n", + "Dividing by number of accumulations: 20\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load darks time: 0.035 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Subtracting dark field\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Dark Field correction time: 0.068 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No clean flats mode\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Flats\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Normalising flat time: 0.079 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Correcting Flatfield\n", + "Dividing by 24 flats, one for each image\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Flat Field correction time: 0.356 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No prefilter mode\n", + " \u001b[0m\n", + "-->>>>>>> Applying field stop\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Field stop time: 0.252 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Demodulating data\n", + "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Demodulation time: 1.819 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Stokes to Quiet Sun\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Stokes Normalising time: 1.706 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Cross-talk correction I to Q,U,V \n", + " ---- >>>>> CT parameters computation of data scan number: 0 .... \n", + "Cross-talk from I to Q: slope = -0.0030 ; off-set = -0.0012 \n", + "Cross-talk from I to U: slope = -0.0031 ; off-set = -0.0008 \n", + "Cross-talk from I to V: slope = -0.0025 ; off-set = -0.0001 \n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- I -> Q,U,V cross talk correction time: 4.084 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "Saving demodulated data to one 'stokes' file per scan\n", + "The scans' DIDs are all unique\n", + "Writing out stokes file as: solo_L2_phi-hrt-stokes_20210914T071515_V02_0149140401.fits\n", + " \n", + "-->>>>>>> RUNNING PMILOS \n", + "Pmilos executable located at: /scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/p-milos/\n", + "It is assumed the wavelength array is given by the hdr\n", + "Wave axis is: [-296.1459 -137.007 -67.0983 0. 70.6113 139.4661]\n", + "Saving data into ./p-milos/run/data/input_tmp.fits for pmilos RTE input\n", + "[6173.0392541 6173.198393 6173.2683017 6173.3354 6173.4060113\n", + " 6173.4748661]\n", + " ---- >>>>> Inverting data scan number: 0 .... \n", + "(2048, 2048, 13)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- PMILOS RTE Run Time: 32.692 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "--------------------------------------------------------------\n", + "------------ Reduction Complete: 44.921 seconds\n", + "--------------------------------------------------------------\n", + "\u001b\u001b[0m\r" + ] + } + ], "source": [ "#Example RUN the pipe\n", "%load_ext autoreload\n", @@ -183,7 +306,7 @@ "\n", "#insert name of your input file\n", "\n", - "phihrt_pipe('./input_jsons/your_input_file.json')" + "stokes = phihrt_pipe('./input_jsons/name_of_your_input_file.json')" ] }, { @@ -192,14 +315,16 @@ "metadata": {}, "outputs": [], "source": [ - "#The better way is to run:\n", + "#Or can run in terminal (either through jupyter or yourself):\n", "import os\n", "cwd = os.getcwd()\n", "os.chdir(cwd + './src/')\n", "\n", - "###############################################\n", - "# CHANGE INPUT FILE LOC IN 'phihrt_pipe'\n", - "###############################################\n", + "#####################################################################\n", + "\n", + "# CHANGE INPUT FILE LOC IN 'phihrt_pipe' function in 'run.py'\n", + "\n", + "#####################################################################\n", "\n", "!python run.py\n", "\n", diff --git a/hrt_pipeline_notebook.ipynb b/hrt_pipeline_notebook.ipynb index e4f0338..f74226c 100644 --- a/hrt_pipeline_notebook.ipynb +++ b/hrt_pipeline_notebook.ipynb @@ -79,7 +79,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -145,11 +145,21 @@ " 'out_rte_filename' : None, #if specific required otherwise will default to standard convention\n", " 'config' : True, #if True, saves a copy of the input file with runtime in the output folder\n", " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", - "}\n", + " 'vers': \"01\", #desired version number, only 2 characters 01 -> 99, if not specified, '01' default\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "##################################################################\n", + "\n", + "# CHANGE NAME OF CONFIG FILE + CREATE\n", "\n", - "####################################\n", - "# CHANGE NAME OF FILE\n", - "####################################\n", + "##################################################################\n", "\n", "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" ] @@ -167,11 +177,124 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "scrolled": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n", + "-------------------------------------------------------------- \u001b[92m\n", + "PHI HRT data reduction software \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Data\n", + "Input contains 1 scan(s)\n", + "Dividing by number of accumulations: 20\n", + "Continuum position at wave: 0\n", + "This scan has been flipped in the Y axis to conform to orientation standards. \n", + " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", + "All the scan(s) have the same dimension\n", + "All the scan(s) have the same continuum wavelength position\n", + "All the scan(s) have the same PMP Temperature Set Point: 50\n", + "Data shape is (2048, 2048, 24, 1)\n", + "All the scan(s) have the same IMGDIRX keyword: YES\n", + "Data reshaped to: (2048, 2048, 4, 6, 1)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load science data time: 0.589 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Flats\n", + "Dividing by number of accumulations: 150\n", + "Flat field shape is (24, 2048, 2048)\n", + "(2048, 2048, 4, 6)\n", + "Continuum position at wave: 5\n", + "The continuum position of the flat field is at 5 index position\n", + "The flat field continuum position is not the same as the data, trying to correct.\n", + "Flat PMP Temperature Set Point: 50\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load flats time: 0.615 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Reading Darks \n", + "Dividing by number of accumulations: 20\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------ Load darks time: 0.035 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Subtracting dark field\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Dark Field correction time: 0.068 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No clean flats mode\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Flats\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Normalising flat time: 0.079 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Correcting Flatfield\n", + "Dividing by 24 flats, one for each image\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Flat Field correction time: 0.356 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> No prefilter mode\n", + " \u001b[0m\n", + "-->>>>>>> Applying field stop\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Field stop time: 0.252 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Demodulating data\n", + "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Demodulation time: 1.819 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Normalising Stokes to Quiet Sun\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- Stokes Normalising time: 1.706 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "-->>>>>>> Cross-talk correction I to Q,U,V \n", + " ---- >>>>> CT parameters computation of data scan number: 0 .... \n", + "Cross-talk from I to Q: slope = -0.0030 ; off-set = -0.0012 \n", + "Cross-talk from I to U: slope = -0.0031 ; off-set = -0.0008 \n", + "Cross-talk from I to V: slope = -0.0025 ; off-set = -0.0001 \n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- I -> Q,U,V cross talk correction time: 4.084 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "Saving demodulated data to one 'stokes' file per scan\n", + "The scans' DIDs are all unique\n", + "Writing out stokes file as: solo_L2_phi-hrt-stokes_20210914T071515_V02_0149140401.fits\n", + " \n", + "-->>>>>>> RUNNING PMILOS \n", + "Pmilos executable located at: /scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/p-milos/\n", + "It is assumed the wavelength array is given by the hdr\n", + "Wave axis is: [-296.1459 -137.007 -67.0983 0. 70.6113 139.4661]\n", + "Saving data into ./p-milos/run/data/input_tmp.fits for pmilos RTE input\n", + "[6173.0392541 6173.198393 6173.2683017 6173.3354 6173.4060113\n", + " 6173.4748661]\n", + " ---- >>>>> Inverting data scan number: 0 .... \n", + "(2048, 2048, 13)\n", + "-------------------------------------------------------------- \u001b[92m\n", + "------------- PMILOS RTE Run Time: 32.692 seconds \u001b[92m\n", + "-------------------------------------------------------------- \u001b[92m\n", + " \u001b[0m\n", + "--------------------------------------------------------------\n", + "------------ Reduction Complete: 44.921 seconds\n", + "--------------------------------------------------------------\n", + "\u001b\u001b[0m\r" + ] + } + ], "source": [ "#Example RUN the pipe\n", "%load_ext autoreload\n", @@ -183,7 +306,7 @@ "\n", "#insert name of your input file\n", "\n", - "phihrt_pipe('./input_jsons/your_input_file.json')" + "stokes = phihrt_pipe('./input_jsons/name_of_your_input_file.json')" ] }, { @@ -192,14 +315,16 @@ "metadata": {}, "outputs": [], "source": [ - "#The better way is to run:\n", + "#Or can run in terminal (either through jupyter or yourself):\n", "import os\n", "cwd = os.getcwd()\n", "os.chdir(cwd + './src/')\n", "\n", - "###############################################\n", - "# CHANGE INPUT FILE LOC IN 'phihrt_pipe'\n", - "###############################################\n", + "#####################################################################\n", + "\n", + "# CHANGE INPUT FILE LOC IN 'phihrt_pipe' function in 'run.py'\n", + "\n", + "#####################################################################\n", "\n", "!python run.py\n", "\n", diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 5cbc6af..c32fec3 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -806,7 +806,7 @@ def phihrt_pipe(input_json_file): pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) except ValueError: - print("Running CMILOS instead!") + print("Running CMILOS txt instead!") cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) else: -- GitLab From b7467857991d71648ee60affd7f47b143afdee44 Mon Sep 17 00:00:00 2001 From: jonas Date: Tue, 23 Nov 2021 16:19:29 +0100 Subject: [PATCH 27/34] header keyword from DC --- .../hrt_pipeline_notebook-checkpoint.ipynb | 356 ------------------ README.md | 2 +- setup.sh | 2 +- src/hrt_pipe.py | 37 +- src/inversions.py | 20 +- src/processes.py | 34 ++ 6 files changed, 83 insertions(+), 368 deletions(-) delete mode 100644 .ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb diff --git a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb b/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb deleted file mode 100644 index f74226c..0000000 --- a/.ipynb_checkpoints/hrt_pipeline_notebook-checkpoint.ipynb +++ /dev/null @@ -1,356 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# **PHI-HRT Pipeline**\n", - "\n", - "_____________\n", - "\n", - "Author: Jonas Sinjan (MPS)
\n", - "Contributor: Daniele Calchetti (MPS)\n", - "\n", - "Reductions Steps\n", - "\n", - "1. read in science data (+scaling) open path option + open for several scans at once\n", - "2. read in flat field (+scaling)- accepts only one flat field fits file\n", - "3. read in dark field (+scaling)\n", - "4. apply dark field (to only science - assumes flat is dark fielded)\n", - "5. option to clean flat field with unsharp masking (Stokes QUV, UV or V)\n", - "6. normalise flat field\n", - "7. apply flat field\n", - "8. prefilter correction\n", - "9. apply field stop\n", - "10. demodulate with const demod matrix\n", - "11. normalise to quiet sun\n", - "12. I -> Q,U,V cross talk correction\n", - "13. rte inversion with cmilos\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 1: Download files\n", - "\n", - "(This requires the hrt_pipeline_env environment - or the correct modules installed with pip (see `requirements.txt`)\n", - "\n", - "Options:\n", - "\n", - "1. Can download manually yourself from the PHI Image Database: https://www2.mps.mpg.de/services/proton/phi/imgdb/\n", - "\n", - " Suggested filters on the database for HRT science data: \n", - " - KEYWORD DETECTOR = 'HRT'
\n", - " - Filename\\* like \\*L1_phi-hrt-ilam_date\\*\n", - " \n", - " Once you find the file you want use the Command Line: \n", - " \n", - " ```\n", - " wget --user yourusername --password yourpassword file_web_address_from_database\n", - " gunzip file.gz\n", - " ```\n", - " \n", - "2. Use the provided script in 'downloads' folder (**Benefit: can download multiple files at once**): `downloads/download_from_db.py`\n", - "\n", - " Instructions:\n", - " 1. From the database find the files you wish to download\n", - " 2. Copy the 'Download File List' that the database will generate\n", - " 3. Paste into the `downloads/file_names.txt` file\n", - " 4. Create a `downloads/.env` file with your MPS Windows login:
\n", - " ```text=\n", - " USER_NAME =\n", - " PHIDATAPASSWORD =\n", - " ``` \n", - " 5. Set the **target download folder** in the `download_from_db.py` file\n", - " 6. Run the file (will require dotenv python module to be installed - included in `hrt_pipeline_env`):\n", - " ```text=\n", - " python download_from_db.py\n", - " ```\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 2: Create Input JSON (config) file" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "#example\n", - "\n", - "data_path = ['data_one.fits', 'data_two.fits', 'etc.fits...'] \n", - "\n", - "#can have as many files as you like, contintue the list\n", - "\n", - "\"\"\"\n", - "IMPORTANT\n", - "\n", - "- files will be procssed with the same flat, dark\n", - "- must have the same continuum position, pmp temp etc - checks will be run, and pipeline will exit if they fail\n", - "- if data is a limb image, the limb in the FOV must be known - ie N, S, E, W etc. before processing\n", - "\"\"\"\n", - "\n", - "dir_data_path = '/path/to/your/data/folder'\n", - "data = [dir_data_path + i for i in data_path]\n", - "\n", - "flat_path = '/path/to/your/flat.fits'\n", - "dark_path = '/path/to/your/dark.fits'\n", - "\n", - "input_dict = {\n", - "\n", - " #input data\n", - " 'data_f' : data, #hrt pipeline allows multiple files at once to be processed \n", - " 'flat_f' : flat_path,\n", - " 'dark_f' : dark_path,\n", - " \n", - " #input/output type + scaling\n", - " 'L1_input' : False, #ignore - in development\n", - " 'L1_8_generate': False, #ignore - in development\n", - " 'scale_data' : True, #leave as True if L1 data\n", - " 'accum_scaling' : True, #leave as True if L1 data\n", - " 'bit_conversion' : True, #leave as True if L1 data\n", - " \n", - " #reduction\n", - " 'dark_c' : True, #apply dark field correction\n", - " 'flat_c' : True, #apply flat field correction\n", - " 'norm_f' : True, #normalise the flats before used (DEFAULT: True)\n", - " 'clean_f' : True, #clean the flat fields with unsharp masking\n", - " 'sigma' : 59, #unsharp masking gaussian width\n", - " 'clean_mode' : \"V\", #options 'QUV', 'UV', 'V' for the unsharp masking\n", - " 'flat_states' : 24, #options 24 (DEFAULT), 4 (one each pol state), 6 (one each wavelength), \n", - " 'prefilter_f': None, #provide the path for the prefilter .fits file\n", - " 'fs_c' : True, #apply the field stop\n", - " 'limb' : None, #for limb images - must know what limb in FOV: 'N','E','W','S'\n", - " 'demod' : True, #demodulate to create the stokes maps\n", - " 'norm_stokes' : True, #normalise the stokes maps to I_continuum\n", - " 'ItoQUV' : False, #apply I-> Q,U,V cross talk correction\n", - " 'ghost_c' : False, #if True, excludes ghost region for ItoQUV ctalk calculation \n", - " 'rte' : False, #options: RTE', 'CE' (classical estimates), 'CE+RTE'\n", - " 'p_milos' : False, #DO NOT USE\n", - " 'cmilos_fits': False, #use cmilos with .fits IO - 16% speed up\n", - " \n", - " #output dir/filenames\n", - " 'out_dir' : None, #directory where you want the output files to go (string)\n", - " 'out_stokes_file' : False, #if True, will save the final stokes array to fits file(s)\n", - " 'out_stokes_filename' : None, #if specific required otherwise will default to standard convention\n", - " 'out_rte_filename' : None, #if specific required otherwise will default to standard convention\n", - " 'config' : True, #if True, saves a copy of the input file with runtime in the output folder\n", - " 'out_intermediate': False, #if True, save intermediate steps to fits files in the output folder (OUT_STOKES_FILE MUST BE SET TO TRUE)\n", - " 'vers': \"01\", #desired version number, only 2 characters 01 -> 99, if not specified, '01' default\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "##################################################################\n", - "\n", - "# CHANGE NAME OF CONFIG FILE + CREATE\n", - "\n", - "##################################################################\n", - "\n", - "#json.dump(input_dict, open(f\"./input_jsons/name_your_input_file.json\", \"w\")) #uncomment to run" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Step 3: Run the Pipeline\n", - "\n", - "Two options\n", - "1. Run within notebook
\n", - "2. Run in Terminal" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The autoreload extension is already loaded. To reload it, use:\n", - " %reload_ext autoreload\n", - "-------------------------------------------------------------- \u001b[92m\n", - "PHI HRT data reduction software \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Data\n", - "Input contains 1 scan(s)\n", - "Dividing by number of accumulations: 20\n", - "Continuum position at wave: 0\n", - "This scan has been flipped in the Y axis to conform to orientation standards. \n", - " File: /data/slam/home/sinjan/fits_files/solo_L1_phi-hrt-ilam_20210914T071515_V202110260809C_0149140401.fits\n", - "All the scan(s) have the same dimension\n", - "All the scan(s) have the same continuum wavelength position\n", - "All the scan(s) have the same PMP Temperature Set Point: 50\n", - "Data shape is (2048, 2048, 24, 1)\n", - "All the scan(s) have the same IMGDIRX keyword: YES\n", - "Data reshaped to: (2048, 2048, 4, 6, 1)\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load science data time: 0.589 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Flats\n", - "Dividing by number of accumulations: 150\n", - "Flat field shape is (24, 2048, 2048)\n", - "(2048, 2048, 4, 6)\n", - "Continuum position at wave: 5\n", - "The continuum position of the flat field is at 5 index position\n", - "The flat field continuum position is not the same as the data, trying to correct.\n", - "Flat PMP Temperature Set Point: 50\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load flats time: 0.615 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Reading Darks \n", - "Dividing by number of accumulations: 20\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------ Load darks time: 0.035 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Subtracting dark field\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Dark Field correction time: 0.068 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> No clean flats mode\n", - " \u001b[0m\n", - "-->>>>>>> Normalising Flats\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Normalising flat time: 0.079 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Correcting Flatfield\n", - "Dividing by 24 flats, one for each image\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Flat Field correction time: 0.356 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> No prefilter mode\n", - " \u001b[0m\n", - "-->>>>>>> Applying field stop\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Field stop time: 0.252 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Demodulating data\n", - "Using a constant demodulation matrix for a PMP TEMP of 50 deg\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Demodulation time: 1.819 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Normalising Stokes to Quiet Sun\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- Stokes Normalising time: 1.706 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "-->>>>>>> Cross-talk correction I to Q,U,V \n", - " ---- >>>>> CT parameters computation of data scan number: 0 .... \n", - "Cross-talk from I to Q: slope = -0.0030 ; off-set = -0.0012 \n", - "Cross-talk from I to U: slope = -0.0031 ; off-set = -0.0008 \n", - "Cross-talk from I to V: slope = -0.0025 ; off-set = -0.0001 \n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- I -> Q,U,V cross talk correction time: 4.084 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "Saving demodulated data to one 'stokes' file per scan\n", - "The scans' DIDs are all unique\n", - "Writing out stokes file as: solo_L2_phi-hrt-stokes_20210914T071515_V02_0149140401.fits\n", - " \n", - "-->>>>>>> RUNNING PMILOS \n", - "Pmilos executable located at: /scratch/slam/sinjan/solo_attic_fits/hrt_pipeline/p-milos/\n", - "It is assumed the wavelength array is given by the hdr\n", - "Wave axis is: [-296.1459 -137.007 -67.0983 0. 70.6113 139.4661]\n", - "Saving data into ./p-milos/run/data/input_tmp.fits for pmilos RTE input\n", - "[6173.0392541 6173.198393 6173.2683017 6173.3354 6173.4060113\n", - " 6173.4748661]\n", - " ---- >>>>> Inverting data scan number: 0 .... \n", - "(2048, 2048, 13)\n", - "-------------------------------------------------------------- \u001b[92m\n", - "------------- PMILOS RTE Run Time: 32.692 seconds \u001b[92m\n", - "-------------------------------------------------------------- \u001b[92m\n", - " \u001b[0m\n", - "--------------------------------------------------------------\n", - "------------ Reduction Complete: 44.921 seconds\n", - "--------------------------------------------------------------\n", - "\u001b\u001b[0m\r" - ] - } - ], - "source": [ - "#Example RUN the pipe\n", - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "import sys\n", - "sys.path.insert(1, './src/')\n", - "from hrt_pipe import phihrt_pipe\n", - "\n", - "#insert name of your input file\n", - "\n", - "stokes = phihrt_pipe('./input_jsons/name_of_your_input_file.json')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Or can run in terminal (either through jupyter or yourself):\n", - "import os\n", - "cwd = os.getcwd()\n", - "os.chdir(cwd + './src/')\n", - "\n", - "#####################################################################\n", - "\n", - "# CHANGE INPUT FILE LOC IN 'phihrt_pipe' function in 'run.py'\n", - "\n", - "#####################################################################\n", - "\n", - "!python run.py\n", - "\n", - "os.chdir(cwd)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "hrt_pipeline_env", - "language": "python", - "name": "hrt_pipeline_env" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.12" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/README.md b/README.md index eb45d3c..57ef7af 100755 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ First let jupyter notebook know the environment exists: ``` python -m ipykernel install --user --name hrt_pipeline_env ``` -Now start the notebook +Now start the notebook
############################################################## 5. Download files - see **DOWNLOAD INPUT FILES** Section diff --git a/setup.sh b/setup.sh index 1b2649c..9624326 100644 --- a/setup.sh +++ b/setup.sh @@ -28,7 +28,7 @@ make cd .. -#conda env create -f environment.yml +conda env create -f environment.yml #pip install -r requrements.txt source activate hrt_pipeline_env diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index c32fec3..5fc9ab9 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -111,9 +111,11 @@ def phihrt_pipe(input_json_file): SPGYlib ''' + version = 'V1.0 November 23rd 2021' printc('--------------------------------------------------------------',bcolors.OKGREEN) printc('PHI HRT data reduction software ',bcolors.OKGREEN) + printc('Version: '+version,bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) #----------------- @@ -277,6 +279,8 @@ def phihrt_pipe(input_json_file): cols = slice(start_col,start_col + data_size[1]) ceny = slice(data_size[0]//2 - data_size[0]//4, data_size[0]//2 + data_size[0]//4) cenx = slice(data_size[1]//2 - data_size[1]//4, data_size[1]//2 + data_size[1]//4) + + hdr_arr = setup_header(hdr_arr) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------ Load science data time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) @@ -416,6 +420,11 @@ def phihrt_pipe(input_json_file): if out_intermediate: data_darkc = data.copy() + DID_dark = h['PHIDATID'] + + for hdr in hdr_arr: + hdr['CAL_DARK'] = DID_dark + else: print(" ") printc('-->>>>>>> No dark mode',color=bcolors.WARNING) @@ -432,6 +441,10 @@ def phihrt_pipe(input_json_file): start_time = time.time() flat = unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode, clean_f = "blurring") + + for hdr in hdr_arr: + hdr['CAL_USH'] = clean_mode + hdr['SIGM_USH'] = sigma printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Cleaning flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) @@ -466,6 +479,11 @@ def phihrt_pipe(input_json_file): if out_intermediate: data_flatc = data.copy() + DID_flat = header_flat['PHIDATID'] + + for hdr in hdr_arr: + hdr['CAL_FLAT'] = DID_flat + printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -499,6 +517,9 @@ def phihrt_pipe(input_json_file): data = prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages) + for hdr in hdr_arr: + hdr['CAL_PRE'] = prefilter_f + data_PFc = data.copy() # DC 20211116 printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -538,6 +559,9 @@ def phihrt_pipe(input_json_file): start_time = time.time() data,_ = demod_hrt(data, pmp_temp) + + for hdr in hdr_arr: + hdr['CAL_IPOL'] = 'HRT'+pmp_temp if out_intermediate: data_demod = data.copy() @@ -569,11 +593,7 @@ def phihrt_pipe(input_json_file): for scan in range(data_shape[-1]): - #I_c = np.mean(data[ceny,cenx,0,cpos_arr[0],int(scan)]) #mean of central 1k x 1k of continuum stokes I - #I_c = np.mean(data[50:500,700:1700,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun north limb - #I_c = np.mean(data[1500:2000,800:1300,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun south limb - #I_c = np.mean(data[350:1700,200:900,0,cpos_arr[0],int(scan)]) # West limb - limb_copy = np.copy(data) + #limb_copy = np.copy(data) #from Daniele Calchetti @@ -604,7 +624,7 @@ def phihrt_pipe(input_json_file): I_c[scan] = np.mean(data[Ic_temp,0,cpos_arr[0],int(scan)]) data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c[scan] Ic_mask[...,scan] = Ic_temp - hdr_arr[scan]['CAL_NORM'] = round(I_c[scan],0) # DC 20211116 + hdr_arr[scan]['CAL_NORM'] = round(I_c[scan],4) # DC 20211116 printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -648,6 +668,11 @@ def phihrt_pipe(input_json_file): scan_hdr['CAL_CRT1'] = round(ctalk_params[offset,q],4) #I-Q offset scan_hdr['CAL_CRT3'] = round(ctalk_params[offset,u],4) #I-U offset scan_hdr['CAL_CRT5'] = round(ctalk_params[offset,v],4) #I-V offset + + scan_hdr['CAL_CRT6'] = 0 #V-Q slope + scan_hdr['CAL_CRT8'] = 0 #V-U slope + scan_hdr['CAL_CRT7'] = 0 #V-Q offset + scan_hdr['CAL_CRT9'] = 0 #V-U offset try: data = CT_ItoQUV(data, CTparams, norm_stokes, cpos_arr, Ic_mask) diff --git a/src/inversions.py b/src/inversions.py index 6efed5f..c38a6cf 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -175,6 +175,10 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + hdr_scan['RTE_MOD'] = rte + hdr_scan['RTE_SW'] = 'cmilos' + hdr_scan['RTE_ITER'] = str(15) + if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) @@ -192,10 +196,10 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root - # with fits.open(file_path) as hdu_list: - # hdu_list[0].header = hdr_scan - # hdu_list[0].data = rte_data_products - # hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products + hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) #blos with fits.open(file_path) as hdu_list: @@ -408,6 +412,10 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + hdr_scan['RTE_MOD'] = rte + hdr_scan['RTE_SW'] = 'cmilos-fits' + hdr_scan['RTE_ITER'] = str(15) + if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) @@ -609,6 +617,10 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + hdr_scan['RTE_MOD'] = rte + hdr_scan['RTE_SW'] = 'pmilos' + hdr_scan['RTE_ITER'] = str(15) + if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) diff --git a/src/processes.py b/src/processes.py index 9e54c52..0588bd4 100644 --- a/src/processes.py +++ b/src/processes.py @@ -5,6 +5,40 @@ from utils import * import os import time +def setup_header(hdr_arr): + k = ['CAL_FLAT','CAL_USH','SIGM_USH', + 'CAL_PRE','CAL_GHST','CAL_REAL', + 'CAL_CRT0','CAL_CRT1','CAL_CRT2','CAL_CRT3','CAL_CRT4','CAL_CRT5', + 'CAL_CRT6','CAL_CRT7','CAL_CRT8','CAL_CRT9', + 'CAL_NORM','CAL_FRIN','CAL_PSF','CAL_IPOL', + 'CAL_SCIP','RTE_MOD','RTE_SW','RTE_ITER'] + + v = [0,' ',' ', + ' ','None ','NA', + 0,0,0,0,0,0, + 0,0,0,0, + ' ','NA','NA',' ', + 'None',' ',' ',4294967295] + + c = ['Onboard calibrated for gain table','Unsharp masking correction','Sigma for unsharp masking [px]', + 'Prefilter correction (DID/file)','Ghost correction (name + version of module','Prealigment of images before demodulation', + 'cross-talk from I to Q (slope)','cross-talk from I to Q (offset)','cross-talk from I to U (slope)','cross-talk from I to U (offset)','cross-talk from I to V (slope)','cross-talk from I to V (offset)', + 'cross-talk from V to Q (slope)','cross-talk from V to Q (offset)','cross-talk from V to U (slope)','cross-talk from V to U (offset)', + 'Normalization (normalization constant PROC_Ic)','Fringe correction (name + version of module)','Onboard calibrated for instrumental PSF','Onboard calibrated for instrumental polarization', + 'Onboard scientific data analysis','Inversion mode','Inversion software','Number RTE inversion iterations'] + + for h in hdr_arr: + for i in range(len(k)): + if k[i] in h: # Check for existence + h[k[i]] = v[i] + else: + if i==0: + h.set(k[i], v[i], c[i], after='CAL_DARK') + else: + h.set(k[i], v[i], c[i], after=k[i-1]) + return hdr_arr + + def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_exists, imgdirx_flipped, cpos_arr) -> np.ndarray: """ load, scale, flip and correct flat -- GitLab From d27153caaddc1015f61cbea12a14f97141bb216f Mon Sep 17 00:00:00 2001 From: jonas Date: Tue, 23 Nov 2021 16:32:45 +0100 Subject: [PATCH 28/34] Intermediate demod file is normalised --- src/hrt_pipe.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 5fc9ab9..49a342a 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -563,8 +563,6 @@ def phihrt_pipe(input_json_file): for hdr in hdr_arr: hdr['CAL_IPOL'] = 'HRT'+pmp_temp - if out_intermediate: - data_demod = data.copy() printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Demodulation time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) @@ -626,7 +624,9 @@ def phihrt_pipe(input_json_file): Ic_mask[...,scan] = Ic_temp hdr_arr[scan]['CAL_NORM'] = round(I_c[scan],4) # DC 20211116 - + if out_intermediate: + data_demod_normed = data.copy() + printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Stokes Normalising time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -798,7 +798,7 @@ def phihrt_pipe(input_json_file): if demod: # DC 20211116 with fits.open(scan) as hdu_list: print(f"Writing intermediate file as: {scan_name_list[count]}_demodulated.fits") - hdu_list[0].data = data_demod[:,:,:,:,count] + hdu_list[0].data = data_demod_normed[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) -- GitLab From 40114bdcadd8ebea4a2ae01b41a6169ae495ff02 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 26 Nov 2021 16:39:09 +0100 Subject: [PATCH 29/34] azi = pi - azi if imgdirx flipped --- src/hrt_pipe.py | 8 +- src/inversions.py | 323 ++++++++++++++-------------------------------- src/utils.py | 2 +- 3 files changed, 104 insertions(+), 229 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 49a342a..08ae87d 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -828,18 +828,18 @@ def phihrt_pipe(input_json_file): if p_milos: try: - pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) + pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) except ValueError: print("Running CMILOS txt instead!") - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: if cmilos_fits_opt: - cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) + cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, out_rte_filename, out_dir, vers = vrs) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: print(" ") diff --git a/src/inversions.py b/src/inversions.py index c38a6cf..701e98b 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -6,27 +6,100 @@ import time import subprocess def create_output_filenames(filename, DID, version = '01'): - try: - file_start = filename.split('solo_')[1] - file_start = 'solo_' + file_start - L2_str = file_start.replace('L1', 'L2') - versioned = L2_str.split('V')[0] + 'V' + version + '_' + DID + '.fits' - stokes_file = versioned.replace('ilam', 'stokes') - icnt_file = versioned.replace('ilam', 'icnt') - bmag_file = versioned.replace('ilam', 'bmag') - bazi_file = versioned.replace('ilam', 'bazi') - binc_file = versioned.replace('ilam', 'binc') - blos_file = versioned.replace('ilam', 'blos') - vlos_file = versioned.replace('ilam', 'vlos') - - return stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file - - except Exception: - print("The input file: {file_path} does not contain 'L1'") - raise KeyError - - -def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): + """ + creating the L2 output filenames from the input, assuming L1 + """ + try: + file_start = filename.split('solo_')[1] + file_start = 'solo_' + file_start + L2_str = file_start.replace('L1', 'L2') + versioned = L2_str.split('V')[0] + 'V' + version + '_' + DID + '.fits' + stokes_file = versioned.replace('ilam', 'stokes') + icnt_file = versioned.replace('ilam', 'icnt') + bmag_file = versioned.replace('ilam', 'bmag') + bazi_file = versioned.replace('ilam', 'bazi') + binc_file = versioned.replace('ilam', 'binc') + blos_file = versioned.replace('ilam', 'blos') + vlos_file = versioned.replace('ilam', 'vlos') + + return stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file + + except Exception: + print("The input file: {file_path} does not contain 'L1'") + raise KeyError + + +def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers): + """ + write out the L2 files + stokes + taking care of the azimuth definition if the image is flipped + """ + + if imgdirx_flipped: + print("Input image has been flipped as per convention - converting Azimuth to convention") + azi = rte_data_products[3,:,:].copy() + rte_data_products[3,:,:] = np.pi - azi + + if out_rte_filename is None: + filename_root = str(file_path.split('.fits')[0][-10:]) + stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) + + else: + if isinstance(out_rte_filename, list): + filename_root = out_rte_filename[scan] + + elif isinstance(out_rte_filename, str): + filename_root = out_rte_filename + + else: + filename_root = str(file_path.split('.fits')[0][-10:]) + print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") + + blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root + + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products + hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) + + #blos + with fits.open(file_path) as hdu_list: + hdu_list[0].header= hdr_scan + hdu_list[0].data = rte_data_products[5,:,:] + hdu_list.writeto(out_dir+blos_file, overwrite=True) + + #bazi + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products[3,:,:] + hdu_list.writeto(out_dir+bazi_file, overwrite=True) + + #binc + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products[2,:,:] + hdu_list.writeto(out_dir+binc_file, overwrite=True) + + #bmag + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products[1,:,:] + hdu_list.writeto(out_dir+bmag_file, overwrite=True) + + #vlos + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products[4,:,:] + hdu_list.writeto(out_dir+vlos_file, overwrite=True) + + #Icnt + with fits.open(file_path) as hdu_list: + hdu_list[0].header = hdr_scan + hdu_list[0].data = rte_data_products[0,:,:] + hdu_list.writeto(out_dir+icnt_file, overwrite=True) + + +def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -98,11 +171,8 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field if rte == 'CE+RTE': rte_on = subprocess.call(cmd+" 6 15 1 0 dummy_in.txt > dummy_out.txt",shell=True) - #print(rte_on) - printc(' ---- >>>>> Reading results.... ',color=bcolors.OKGREEN) del_dummy = subprocess.call("rm dummy_in.txt",shell=True) - #print(del_dummy) res = np.loadtxt('dummy_out.txt') npixels = res.shape[0]/12. @@ -144,25 +214,6 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field #np.savez_compressed(out_dir+'_RTE', rte_invs=rte_invs, rte_invs_noth=rte_invs_noth) del_dummy = subprocess.call("rm dummy_out.txt",shell=True) - #print(del_dummy) - - """ - #vlos S/C vorrection - v_x, v_y, v_z = hdr['HCIX_VOB']/1000, hdr['HCIY_VOB']/1000, hdr['HCIZ_VOB']/1000 - - #need line of sight velocity, should be total HCI velocity in km/s, with sun at origin. - #need to take care for velocities moving towards the sun, (ie negative) #could use continuum position as if towards or away - - if cpos_arr[scan] == 5: #moving away, redshifted - dir_factor = 1 - - elif cpos_arr[scan] == 0: #moving towards, blueshifted - dir_factor == -1 - - v_tot = dir_factor*math.sqrt(v_x**2 + v_y**2+v_z**2) #in km/s - - rte_invs_noth[8,:,:] = rte_invs_noth[8,:,:] - v_tot - """ rte_data_products = np.zeros((6,rte_invs_noth.shape[1],rte_invs_noth.shape[2])) @@ -179,70 +230,14 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field hdr_scan['RTE_SW'] = 'cmilos' hdr_scan['RTE_ITER'] = str(15) - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) - - else: - if isinstance(out_rte_filename, list): - filename_root = out_rte_filename[scan] - - elif isinstance(out_rte_filename, str): - filename_root = out_rte_filename - - else: - filename_root = str(file_path.split('.fits')[0][-10:]) - print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - - blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root - - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products - hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) - - #blos - with fits.open(file_path) as hdu_list: - hdu_list[0].header= hdr_scan - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+blos_file, overwrite=True) - - #bazi - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+bazi_file, overwrite=True) - - #binc - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+binc_file, overwrite=True) - - #bmag - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+bmag_file, overwrite=True) - - #vlos - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+vlos_file, overwrite=True) - - #Icnt - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+icnt_file, overwrite=True) + write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- CMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) -def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): +def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -303,25 +298,8 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, hdr['LAMBDA4'] = wave_axis[4] hdr['LAMBDA5'] = wave_axis[5] - #write out data to temp fits for cmilos-fits input input_arr = np.transpose(sdata, axes = (3,2,0,1)) #must transpose due to cfitsio (wl,pol,y,x) #3201 originally - - # DC CHANGE (same number of digits of cmilos) -# hdr['LAMBDA0'] = float('%e' % wave_axis[0])#needs it in Angstrom 6173.1 etc -# hdr['LAMBDA1'] = float('%e' % wave_axis[1]) -# hdr['LAMBDA2'] = float('%e' % wave_axis[2]) -# hdr['LAMBDA3'] = float('%e' % wave_axis[3]) -# hdr['LAMBDA4'] = float('%e' % wave_axis[4]) -# hdr['LAMBDA5'] = float('%e' % wave_axis[5]) -# printc('-->>>>>>> CHANGING DATA PRECISION ',color=bcolors.OKGREEN) -# for w in range(l): -# for s in range(p): -# for i in range(y): -# for j in range(x): -# input_arr[w,s,i,j] = float('%e' % input_arr[w,s,i,j]) - # DC CHANGE END - hdu1 = fits.PrimaryHDU(data=input_arr, header = hdr) #mask @@ -373,9 +351,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, Constant source function Slope source function Minimum chisqr value - """ - """ Direct from cmilos-fits/milos.c inv->iter = malloc(npix*sizeof(int)); inv->B = malloc(npix*sizeof(double)); @@ -390,9 +366,6 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, inv->S1 = malloc(npix*sizeof(double)); inv->nchisqrf = malloc(npix*sizeof(double)); - """ - - """ noise_in_V = np.mean(data[:,:,3,cpos_arr[0],:]) low_values_flags = np.max(np.abs(data[:,:,3,:,scan]),axis=-1) < noise_in_V # Where values are low @@ -416,57 +389,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, hdr_scan['RTE_SW'] = 'cmilos-fits' hdr_scan['RTE_ITER'] = str(15) - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) - else: - if isinstance(out_rte_filename, list): - filename_root = out_rte_filename[scan] - - elif isinstance(out_rte_filename, str): - filename_root = out_rte_filename - - else: - filename_root = str(file_path.split('.fits')[0][-10:]) - print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") - - blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root - - #blos - with fits.open(file_path) as hdu_list: - hdu_list[0].header= hdr_scan - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+blos_file, overwrite=True) - - #bazi - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+bazi_file, overwrite=True) - - #binc - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+binc_file, overwrite=True) - - #bmag - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+bmag_file, overwrite=True) - - #vlos - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+vlos_file, overwrite=True) - - #Icnt - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+icnt_file, overwrite=True) + write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) @@ -474,7 +397,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, -def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, out_rte_filename, out_dir, vers = '01'): +def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using PMILOS """ @@ -621,55 +544,7 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field hdr_scan['RTE_SW'] = 'pmilos' hdr_scan['RTE_ITER'] = str(15) - if out_rte_filename is None: - filename_root = str(file_path.split('.fits')[0][-10:]) - stokes_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file, vlos_file = create_output_filenames(file_path, filename_root, version = vers) - else: - filename_root = out_rte_filename - - blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root - - # with fits.open(file_path) as hdu_list: - # hdu_list[0].header = hdr - # hdu_list[0].data = rte_data_products - # hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) - - #blos - with fits.open(file_path) as hdu_list: - hdu_list[0].header= hdr_scan - hdu_list[0].data = rte_data_products[5,:,:] - hdu_list.writeto(out_dir+blos_file, overwrite=True) - - #bazi - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[3,:,:] - hdu_list.writeto(out_dir+bazi_file, overwrite=True) - - #binc - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[2,:,:] - hdu_list.writeto(out_dir+binc_file, overwrite=True) - - #bmag - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[1,:,:] - hdu_list.writeto(out_dir+bmag_file, overwrite=True) - - #vlos - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[4,:,:] - hdu_list.writeto(out_dir+vlos_file, overwrite=True) - - #Icnt - with fits.open(file_path) as hdu_list: - hdu_list[0].header = hdr_scan - hdu_list[0].data = rte_data_products[0,:,:] - hdu_list.writeto(out_dir+icnt_file, overwrite=True) - + write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- PMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) diff --git a/src/utils.py b/src/utils.py index 6fe3aee..f3ea671 100755 --- a/src/utils.py +++ b/src/utils.py @@ -243,7 +243,7 @@ def check_IMGDIRX(hdr_arr): else: header_imgdirx_exists = False print("Not all the scan(s) contain the 'IMGDIRX' keyword! Assuming all not flipped - Proceed with caution") - return header_imgdirx_exists, None + return header_imgdirx_exists, False def compare_IMGDIRX(flat,header_imgdirx_exists,imgdirx_flipped,header_fltdirx_exists,fltdirx_flipped): -- GitLab From a7b87ab122b89da50c9c8bdf89684690725386f8 Mon Sep 17 00:00:00 2001 From: jonas Date: Mon, 13 Dec 2021 17:25:34 +0100 Subject: [PATCH 30/34] adding keywords --- src/hrt_pipe.py | 19 ++++++++++++++----- src/inversions.py | 12 +++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 08ae87d..fc4f8a1 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -286,7 +286,9 @@ def phihrt_pipe(input_json_file): printc(f"------------ Load science data time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) - + for hdr in hdr_arr: + hdr['VERS_SW'] = version #version of pipeline + hdr['VERSION'] = vrs #version of the file V01 #----------------- # READ FLAT FIELDS #----------------- @@ -420,7 +422,7 @@ def phihrt_pipe(input_json_file): if out_intermediate: data_darkc = data.copy() - DID_dark = h['PHIDATID'] + DID_dark = h['FILENAME'] for hdr in hdr_arr: hdr['CAL_DARK'] = DID_dark @@ -479,10 +481,14 @@ def phihrt_pipe(input_json_file): if out_intermediate: data_flatc = data.copy() - DID_flat = header_flat['PHIDATID'] - + #DID_flat = header_flat['PHIDATID'] + if '/' in flat_f: + filename = flat_f.split('/')[-1] + else: + filename = flat_f + for hdr in hdr_arr: - hdr['CAL_FLAT'] = DID_flat + hdr['CAL_FLAT'] = filename#DID_flat - not the FILENAME keyword, in case we are trying with extra cleaned flats printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) @@ -765,6 +771,9 @@ def phihrt_pipe(input_json_file): stokes_file = create_output_filenames(scan, scan_name_list[count], version = vrs)[0] + ntime = datetime.datetime.now() + hdr_arr[count]['DATE'] = ntime.strftime("%Y-%m-%dT%H:%M:%S") + with fits.open(scan) as hdu_list: print(f"Writing out stokes file as: {stokes_file}") hdu_list[0].data = data[:,:,:,:,count] diff --git a/src/inversions.py b/src/inversions.py index 701e98b..ad63efb 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -4,6 +4,7 @@ from utils import * import os import time import subprocess +import datetime def create_output_filenames(filename, DID, version = '01'): """ @@ -57,6 +58,9 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx blos_file, icnt_file, bmag_file, bazi_file, binc_file, blos_file = filename_root, filename_root, filename_root, filename_root, filename_root, filename_root + ntime = datetime.datetime.now() + hdr_scan['DATE'] = ntime.strftime("%Y-%m-%dT%H:%M:%S") + with fits.open(file_path) as hdu_list: hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products @@ -64,36 +68,42 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #blos with fits.open(file_path) as hdu_list: - hdu_list[0].header= hdr_scan + hdr_scan['FILENAME'] = blos_file + hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[5,:,:] hdu_list.writeto(out_dir+blos_file, overwrite=True) #bazi with fits.open(file_path) as hdu_list: + hdr_scan['FILENAME'] = bazi_file hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[3,:,:] hdu_list.writeto(out_dir+bazi_file, overwrite=True) #binc with fits.open(file_path) as hdu_list: + hdr_scan['FILENAME'] = binc_file hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[2,:,:] hdu_list.writeto(out_dir+binc_file, overwrite=True) #bmag with fits.open(file_path) as hdu_list: + hdr_scan['FILENAME'] = bmag_file hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[1,:,:] hdu_list.writeto(out_dir+bmag_file, overwrite=True) #vlos with fits.open(file_path) as hdu_list: + hdr_scan['FILENAME'] = vlos_file hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[4,:,:] hdu_list.writeto(out_dir+vlos_file, overwrite=True) #Icnt with fits.open(file_path) as hdu_list: + hdr_scan['FILENAME'] = icnt_file hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[0,:,:] hdu_list.writeto(out_dir+icnt_file, overwrite=True) -- GitLab From 65107086e8028260336095ad70d605cac47a700c Mon Sep 17 00:00:00 2001 From: jonas Date: Wed, 15 Dec 2021 10:39:18 +0100 Subject: [PATCH 31/34] rad to degrees change --- src/inversions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inversions.py b/src/inversions.py index ad63efb..51a1ad0 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -39,7 +39,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx if imgdirx_flipped: print("Input image has been flipped as per convention - converting Azimuth to convention") azi = rte_data_products[3,:,:].copy() - rte_data_products[3,:,:] = np.pi - azi + rte_data_products[3,:,:] = 180 - azi if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) -- GitLab From 6e3680a24392327763c567d5579d3b4e0a3616bb Mon Sep 17 00:00:00 2001 From: jonas Date: Wed, 15 Dec 2021 13:02:43 +0100 Subject: [PATCH 32/34] PARENT + HISTORY keywords --- src/hrt_pipe.py | 9 +++++++-- src/inversions.py | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index fc4f8a1..e6c540d 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -111,7 +111,7 @@ def phihrt_pipe(input_json_file): SPGYlib ''' - version = 'V1.0 November 23rd 2021' + version = 'V1.1 December 15th 2021' printc('--------------------------------------------------------------',bcolors.OKGREEN) printc('PHI HRT data reduction software ',bcolors.OKGREEN) @@ -733,6 +733,10 @@ def phihrt_pipe(input_json_file): #WRITE OUT STOKES VECTOR #----------------- + #rewrite the PARENT keyword to the original FILENAME + for count, scan in enumerate(data_f): + hdr_arr[count]['PARENT'] = hdr_arr[count]['FILENAME'] + #these two ifs need to be outside out_stokes_file if statement - needed for inversion if out_dir[-1] != "/": print("Desired Output directory missing / character, will be added") @@ -743,7 +747,6 @@ def phihrt_pipe(input_json_file): print(f"{out_dir} does not exist -->>>>>>> Creating it") os.makedirs(out_dir) - if out_stokes_file: print(" ") @@ -773,6 +776,8 @@ def phihrt_pipe(input_json_file): ntime = datetime.datetime.now() hdr_arr[count]['DATE'] = ntime.strftime("%Y-%m-%dT%H:%M:%S") + hdr_arr[count]['FILENAME'] = stokes_file + hdr_arr[count]['HISTORY'] = f"Reduced with hrt-pipeline {version}, to create a STOKES file. Dark field Applied: {dark_f}. Flat field Applied: {flat_f}, Flat Unsharp Masked: {clean_f}. Flat normalised: {norm_f}. I->QUV ctalk: {ItoQUV}." with fits.open(scan) as hdu_list: print(f"Writing out stokes file as: {stokes_file}") diff --git a/src/inversions.py b/src/inversions.py index 51a1ad0..7bdfca4 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -61,6 +61,23 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx ntime = datetime.datetime.now() hdr_scan['DATE'] = ntime.strftime("%Y-%m-%dT%H:%M:%S") + version_k = hdr_scan['VERS_SW'] + if '.fits' in hdr_scan['CAL_DARK']: + dark_f_k = 'True' + else: + dark_f_k = 'False' + if '.fits' in hdr_scan['CAL_FLAT']: + flat_f_k = 'True' + else: + flat_f_k = 'False' + clean_f_k = hdr_scan['CAL_USH'] + if hdr_scan['CAL_CRT1'] > 0: + ItoQUV_k ='True' + else: + ItoQUV_k = 'False' + rte_sw_k = hdr_scan['RTE_SW'] + rte_mod_k = hdr_scan['RTE_MOD'] + with fits.open(file_path) as hdu_list: hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products @@ -69,6 +86,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #blos with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = blos_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a Blos file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[5,:,:] hdu_list.writeto(out_dir+blos_file, overwrite=True) @@ -76,6 +94,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #bazi with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = bazi_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a Bazi file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[3,:,:] hdu_list.writeto(out_dir+bazi_file, overwrite=True) @@ -83,6 +102,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #binc with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = binc_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a Binc file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[2,:,:] hdu_list.writeto(out_dir+binc_file, overwrite=True) @@ -90,6 +110,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #bmag with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = bmag_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a Bmag file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[1,:,:] hdu_list.writeto(out_dir+bmag_file, overwrite=True) @@ -97,6 +118,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #vlos with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = vlos_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a vlos file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[4,:,:] hdu_list.writeto(out_dir+vlos_file, overwrite=True) @@ -104,6 +126,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx #Icnt with fits.open(file_path) as hdu_list: hdr_scan['FILENAME'] = icnt_file + hdr_scan['HISTORY'] = f"Reduced with hrt-pipeline {version_k}, to create a Icnt file. Dark field Applied: {dark_f_k}. Flat field Applied: {flat_f_k}, Flat Unsharp Masked Mode: {clean_f_k}. I->QUV ctalk: {ItoQUV_k}. RTE software: {rte_sw_k}. RTE mode: {rte_mod_k}." hdu_list[0].header = hdr_scan hdu_list[0].data = rte_data_products[0,:,:] hdu_list.writeto(out_dir+icnt_file, overwrite=True) -- GitLab From 9d82a65bebc1d07479eabb6f24801413e1c14c13 Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 17 Dec 2021 10:48:47 +0100 Subject: [PATCH 33/34] replace time.time() with time.perf_counter() --- src/hrt_pipe.py | 38 +++++++++++++++++++------------------- src/inversions.py | 12 ++++++------ src/processes.py | 28 ++++++++++++++-------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index e6c540d..c4652dd 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -178,7 +178,7 @@ def phihrt_pipe(input_json_file): print(f"Missing key(s) in the input config file: {e}") raise KeyError - overall_time = time.time() + overall_time = time.perf_counter() if L1_input: #print("L1_input param set to True - Assuming L1 science data") @@ -193,7 +193,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Reading Data',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() if isinstance(data_f, str): data_f = [data_f] @@ -283,7 +283,7 @@ def phihrt_pipe(input_json_file): hdr_arr = setup_header(hdr_arr) printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load science data time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------ Load science data time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) for hdr in hdr_arr: @@ -297,7 +297,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() # flat from IP-5 if '0024151020000' in flat_f or '0024150020000' in flat_f: @@ -351,7 +351,7 @@ def phihrt_pipe(input_json_file): del flat_copy printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------ Load flats time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -368,7 +368,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Reading Darks ',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() try: @@ -400,7 +400,7 @@ def phihrt_pipe(input_json_file): dark = compare_IMGDIRX(dark[np.newaxis],header_imgdirx_exists,imgdirx_flipped,header_drkdirx_exists,drkdirx_flipped)[0] printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------ Load darks time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) except Exception: @@ -440,7 +440,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Cleaning flats with Unsharp Masking',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() flat = unsharp_masking(flat,sigma,flat_pmp_temp,cpos_arr,clean_mode, clean_f = "blurring") @@ -449,7 +449,7 @@ def phihrt_pipe(input_json_file): hdr['SIGM_USH'] = sigma printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Cleaning flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Cleaning flat time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) else: @@ -491,7 +491,7 @@ def phihrt_pipe(input_json_file): hdr['CAL_FLAT'] = filename#DID_flat - not the FILENAME keyword, in case we are trying with extra cleaned flats printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- Flat Field correction time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) except: printc("ERROR, Unable to apply flat fields",color=bcolors.FAIL) @@ -509,7 +509,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Prefilter Correction',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() prefilter_voltages = [-1300.00,-1234.53,-1169.06,-1103.59,-1038.12,-972.644,-907.173,-841.702,-776.231,-710.760,-645.289, -579.818,-514.347,-448.876,-383.404,-317.933,-252.462,-186.991,-121.520,-56.0490,9.42212,74.8932, @@ -529,7 +529,7 @@ def phihrt_pipe(input_json_file): data_PFc = data.copy() # DC 20211116 printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Prefilter correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Prefilter correction time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) else: @@ -562,7 +562,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Demodulating data',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() data,_ = demod_hrt(data, pmp_temp) @@ -571,7 +571,7 @@ def phihrt_pipe(input_json_file): printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Demodulation time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- Demodulation time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) else: @@ -588,7 +588,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Normalising Stokes to Quiet Sun',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() Ic_mask = np.zeros((data_size[0],data_size[1],data_shape[-1]),dtype=bool) I_c = np.ones(data_shape[-1]) @@ -634,7 +634,7 @@ def phihrt_pipe(input_json_file): data_demod_normed = data.copy() printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Stokes Normalising time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- Stokes Normalising time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) else: @@ -651,7 +651,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('-->>>>>>> Cross-talk correction I to Q,U,V ',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() slope, offset = 0, 1 q, u, v = 0, 1, 2 @@ -708,7 +708,7 @@ def phihrt_pipe(input_json_file): raise KeyError("'norm_f' keyword in input config file not set to True \n Aborting") printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- I -> Q,U,V cross talk correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- I -> Q,U,V cross talk correction time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) data *= field_stop[rows,cols, np.newaxis, np.newaxis, np.newaxis] @@ -875,7 +875,7 @@ def phihrt_pipe(input_json_file): print(" ") printc('--------------------------------------------------------------',color=bcolors.OKGREEN) - printc(f'------------ Reduction Complete: {np.round(time.time() - overall_time,3)} seconds',color=bcolors.OKGREEN) + printc(f'------------ Reduction Complete: {np.round(time.perf_counter() - overall_time,3)} seconds',color=bcolors.OKGREEN) printc('--------------------------------------------------------------',color=bcolors.OKGREEN) diff --git a/src/inversions.py b/src/inversions.py index 7bdfca4..7cdaf92 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -159,7 +159,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field for scan in range(int(data_shape[-1])): - start_time = time.time() + start_time = time.perf_counter() file_path = data_f[scan] wave_axis = wve_axis_arr[scan] @@ -266,7 +266,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- CMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- CMILOS RTE Run Time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -297,7 +297,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, for scan in range(int(data_shape[-1])): - start_time = time.time() + start_time = time.perf_counter() file_path = data_f[scan] wave_axis = wve_axis_arr[scan] @@ -425,7 +425,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- CMILOS-FITS RTE Run Time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -457,7 +457,7 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field for scan in range(int(data_shape[-1])): - start_time = time.time() + start_time = time.perf_counter() file_path = data_f[scan] wave_axis = wve_axis_arr[scan] @@ -580,5 +580,5 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx_flipped, out_dir, out_rte_filename, vers) printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- PMILOS RTE Run Time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- PMILOS RTE Run Time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) diff --git a/src/processes.py b/src/processes.py index 0588bd4..07252e8 100644 --- a/src/processes.py +++ b/src/processes.py @@ -46,7 +46,7 @@ def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_ print(" ") printc('-->>>>>>> Reading Flats',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() # flat from IP-5 if '0024151020000' in flat_f or '0024150020000' in flat_f: @@ -99,7 +99,7 @@ def load_flat(flat_f, accum_scaling, bit_conversion, scale_data, header_imgdirx_ del flat_copy printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load flats time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------ Load flats time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return flat @@ -112,7 +112,7 @@ def load_dark(dark_f) -> np.ndarray: print(" ") printc('-->>>>>>> Reading Darks',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() try: dark,_ = get_data(dark_f) @@ -138,7 +138,7 @@ def load_dark(dark_f) -> np.ndarray: raise ValueError printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------ Load darks time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------ Load darks time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return dark @@ -154,13 +154,13 @@ def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: print(" ") print("-->>>>>>> Subtracting dark field") - start_time = time.time() + start_time = time.perf_counter() data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Dark Field correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Dark Field correction time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return data, flat @@ -173,14 +173,14 @@ def normalise_flat(flat, flat_f, ceny, cenx) -> np.ndarray: print(" ") printc('-->>>>>>> Normalising Flats',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() try: norm_fac = np.mean(flat[ceny,cenx, :, :], axis = (0,1))[np.newaxis, np.newaxis, ...] #mean of the central 1k x 1k flat /= norm_fac printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Normalising flat time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Normalising flat time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return flat @@ -294,7 +294,7 @@ def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: print(" ") printc('-->>>>>>> Correcting Flatfield',color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() try: if flat_states == 6: @@ -325,7 +325,7 @@ def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) + printc(f"------------- Flat Field correction time: {np.round(time.perf_counter() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return data @@ -379,7 +379,7 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - print(" ") printc("-->>>>>>> Applying field stop",color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() field_stop_loc = os.path.realpath(__file__) @@ -396,7 +396,7 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Field stop time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return data, field_stop @@ -409,7 +409,7 @@ def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: print(" ") printc("-->>>>>>> Loading ghost field stop",color=bcolors.OKGREEN) - start_time = time.time() + start_time = time.perf_counter() field_stop_loc = os.path.realpath(__file__) field_stop_loc = field_stop_loc.split('src/')[0] + 'field_stop/' @@ -422,7 +422,7 @@ def load_ghost_field_stop(header_imgdirx_exists, imgdirx_flipped) -> np.ndarray: field_stop_ghost = field_stop_ghost[:,::-1] printc('--------------------------------------------------------------',bcolors.OKGREEN) - printc(f"------------- Load Ghost Field Stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) + printc(f"------------- Load Ghost Field Stop time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) return field_stop_ghost -- GitLab From 98d3e1cebc332e93bb0cfe6b6dfc8b4a746bf814 Mon Sep 17 00:00:00 2001 From: jonas Date: Tue, 25 Jan 2022 11:11:49 +0100 Subject: [PATCH 34/34] inversion fix for cropped datasets --- src/hrt_pipe.py | 30 ++++++++++++++++++++++-------- src/inversions.py | 12 ++++++------ src/processes.py | 4 +++- src/utils.py | 9 ++++++--- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index c4652dd..815d5cd 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -436,6 +436,8 @@ def phihrt_pipe(input_json_file): # OPTIONAL Unsharp Masking clean the flat field stokes Q, U or V images #----------------- + flat_copy = flat.copy() + if clean_f and flat_c: print(" ") printc('-->>>>>>> Cleaning flats with Unsharp Masking',color=bcolors.OKGREEN) @@ -622,7 +624,7 @@ def phihrt_pipe(input_json_file): Ic_temp = np.where(Ic_temp>0,1,0) if fs_c: - Ic_temp *= field_stop + Ic_temp *= field_stop[rows,cols] Ic_temp = np.array(Ic_temp, dtype=bool) I_c[scan] = np.mean(data[Ic_temp,0,cpos_arr[0],int(scan)]) @@ -777,7 +779,7 @@ def phihrt_pipe(input_json_file): ntime = datetime.datetime.now() hdr_arr[count]['DATE'] = ntime.strftime("%Y-%m-%dT%H:%M:%S") hdr_arr[count]['FILENAME'] = stokes_file - hdr_arr[count]['HISTORY'] = f"Reduced with hrt-pipeline {version}, to create a STOKES file. Dark field Applied: {dark_f}. Flat field Applied: {flat_f}, Flat Unsharp Masked: {clean_f}. Flat normalised: {norm_f}. I->QUV ctalk: {ItoQUV}." + hdr_arr[count]['HISTORY'] = f"Version: {version}. Dark: {dark_f.split('/')[-1]}. Flat: {flat_f.split('/')[-1]}, Unsharp: {clean_f}. Flat norm: {norm_f}. I->QUV ctalk: {ItoQUV}." with fits.open(scan) as hdu_list: print(f"Writing out stokes file as: {stokes_file}") @@ -801,6 +803,18 @@ def phihrt_pipe(input_json_file): hdu_list[0].data = data_flatc[:,:,:,:,count] hdu_list[0].header = hdr_arr[count] #update the calibration keywords hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) + + with fits.open(flat_f) as hdu_list: + print(f"Writing flat field file as: {flat_f.split('/')[-1]}") + hdu_list[0].data = flat + #update the calibration keywords + hdu_list.writeto(out_dir + f"{flat_f.split('/')[-1]}", overwrite=True) + + with fits.open(flat_f) as hdu_list: + print(f"Writing flat field copy (before US) file as: copy_{flat_f.split('/')[-1]}") + hdu_list[0].data = flat_copy + #update the calibration keywords + hdu_list.writeto(out_dir + "copy_" + f"{flat_f.split('/')[-1]}", overwrite=True) if prefilter_f is not None: # DC 20211116 with fits.open(scan) as hdu_list: @@ -835,25 +849,25 @@ def phihrt_pipe(input_json_file): if limb is not None: - mask = limb_mask*field_stop[...,np.newaxis] + mask = limb_mask*field_stop[rows,cols,np.newaxis] else: - mask = np.ones((data_size[0],data_size[1],data_shape[-1]))*field_stop[...,np.newaxis] + mask = np.ones((data_size[0],data_size[1],data_shape[-1]))*field_stop[rows,cols,np.newaxis] if p_milos: try: - pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) + pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) except ValueError: print("Running CMILOS txt instead!") - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask,imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: if cmilos_fits_opt: - cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) + cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: - cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) + cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = vrs) else: print(" ") diff --git a/src/inversions.py b/src/inversions.py index 7cdaf92..fb7023a 100644 --- a/src/inversions.py +++ b/src/inversions.py @@ -132,7 +132,7 @@ def write_output_inversion(rte_data_products, file_path, scan, hdr_scan, imgdirx hdu_list.writeto(out_dir+icnt_file, overwrite=True) -def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): +def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -257,7 +257,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field rte_data_products[4,:,:] = rte_invs_noth[8,:,:] #vlos rte_data_products[5,:,:] = rte_invs_noth[2,:,:]*np.cos(rte_invs_noth[3,:,:]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + rte_data_products *= mask[np.newaxis, :, :, 0] #field stop, set outside to 0 hdr_scan['RTE_MOD'] = rte hdr_scan['RTE_SW'] = 'cmilos' @@ -270,7 +270,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field printc('--------------------------------------------------------------',bcolors.OKGREEN) -def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): +def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using CMILOS """ @@ -416,7 +416,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, rte_data_products[4,:,:] = rte_out[7,:,:] #vlos rte_data_products[5,:,:] = rte_out[1,:,:]*np.cos(rte_out[2,:,:]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + rte_data_products *= mask[np.newaxis, :, :, 0] #field stop, set outside to 0 hdr_scan['RTE_MOD'] = rte hdr_scan['RTE_SW'] = 'cmilos-fits' @@ -430,7 +430,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, -def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, start_row, start_col, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): +def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, mask, imgdirx_flipped, out_rte_filename, out_dir, vers = '01'): """ RTE inversion using PMILOS """ @@ -571,7 +571,7 @@ def pmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field rte_data_products[4,:,:] = result[:,:,2] #vlos rte_data_products[5,:,:] = result[:,:,1]*np.cos(result[:,:,5]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 + rte_data_products *= mask[np.newaxis, :, :, 0] #field stop, set outside to 0 hdr_scan['RTE_MOD'] = rte hdr_scan['RTE_SW'] = 'pmilos' diff --git a/src/processes.py b/src/processes.py index 07252e8..ce868bc 100644 --- a/src/processes.py +++ b/src/processes.py @@ -157,7 +157,7 @@ def apply_dark_correction(data, flat, dark, rows, cols) -> np.ndarray: start_time = time.perf_counter() data -= dark[rows,cols, np.newaxis, np.newaxis, np.newaxis] - #flat -= dark[..., np.newaxis, np.newaxis] - # all processed flat fields should already be dark corrected + #flat -= dark[..., np.newaxis, np.newaxis] #- # all processed flat fields should already be dark corrected printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Dark Field correction time: {np.round(time.perf_counter() - start_time,3)} seconds",bcolors.OKGREEN) @@ -345,6 +345,8 @@ def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): return v1, index1 data_shape = data.shape + # cop = np.copy(data) + # new_data = np.zeros(data_shape) for scan in range(data_shape[-1]): diff --git a/src/utils.py b/src/utils.py index f3ea671..2944bee 100755 --- a/src/utils.py +++ b/src/utils.py @@ -63,10 +63,13 @@ def get_data(path, scaling = True, bit_convert_scale = True, scale_data = True): printc(f"Dividing by number of accumulations: {accu}",color=bcolors.OKGREEN) if scale_data: #not for commissioning data - - maxRange = fits.open(path)[9].data['PHI_IMG_maxRange'] + + try: + maxRange = fits.open(path)[9].data['PHI_IMG_maxRange'] - data *= maxRange[0]/maxRange[-1] + data *= maxRange[0]/maxRange[-1] + except IndexError: + data *= 81920/128 return data, header -- GitLab

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 Sd)VG*AF^|qgPA8X;(q~lJ_a-Z literal 0 HcmV?d00001 diff --git a/src/hrt_pipe.py b/src/hrt_pipe.py index 410d53c..dd4e5d9 100755 --- a/src/hrt_pipe.py +++ b/src/hrt_pipe.py @@ -74,6 +74,8 @@ def phihrt_pipe(input_json_file): apply dark field correction fs_c: bool, DEFAULT True apply HRT field stop + ghost_c: bool, DEFAULT True + apply HRT field stop and avoid ghost region in CrossTalk parameters computation limb: str, DEFAULT None specify if it is a limb observation, options are 'N', 'S', 'W', 'E' demod: bool, DEFAULT: True @@ -94,6 +96,8 @@ def phihrt_pipe(input_json_file): invert using cmilos, options: 'RTE' for Milne Eddington Inversion, 'CE' for Classical Estimates, 'CE+RTE' for combined out_rte_filename: str, DEFAULT = '' if '', takes last 10 characters of input scan filename (assumes its a DID), change if want other name + out_intermediate: bool, DEFAULT = False + if True, dark corrected, flat corrected, prefilter corrected and demodulated data will be saved p_milos: bool, DEFAULT = True if True, will execute the RTE inversion using the parallel version of the CMILOS code on 16 processors Returns @@ -139,11 +143,13 @@ def phihrt_pipe(input_json_file): flat_states = input_dict['flat_states'] prefilter_f = input_dict['prefilter_f'] fs_c = input_dict['fs_c'] + ghost_c = input_dict['ghost_c'] # DC 20211116 limb = input_dict['limb'] demod = input_dict['demod'] norm_stokes = input_dict['norm_stokes'] - CT_ItoQUV = input_dict['ItoQUV'] - ctalk_params = input_dict['ctalk_params'] + ItoQUV = input_dict['ItoQUV'] +# ctalk_params = input_dict['ctalk_params'] + out_intermediate = input_dict['out_intermediate'] # DC 20211116 rte = input_dict['rte'] p_milos = input_dict['p_milos'] cmilos_fits_opt = input_dict['cmilos_fits_opt'] @@ -326,7 +332,7 @@ def phihrt_pipe(input_json_file): if flat_f[-15:] == '0162201100.fits': # flat_f[-62:] == 'solo_L0_phi-hrt-flat_0667134081_V202103221851C_0162201100.fits' print("This flat has a missing line - filling in with neighbouring pixels") flat_copy = flat.copy() - flat[:,:,1,1] = filling_data(flat_copy[:,:,1,1], 0, mode = {'exact rows':[1345,1346]}, axis=1) + flat[:,:,1,2] = filling_data(flat_copy[:,:,1,2], 0, mode = {'exact rows':[1345,1346]}, axis=1) # flat[1345, 296:, 1, 1] = flat_copy[1344, 296:, 1, 1] # flat[1346, :291, 1, 1] = flat_copy[1345, :291, 1, 1] @@ -401,8 +407,8 @@ def phihrt_pipe(input_json_file): if flat_c == False: flat = np.empty((2048,2048,4,6)) - # if out_intermediate: - # data_darkc = data.copy() + if out_intermediate: + data_darkc = data.copy() else: print(" ") @@ -451,8 +457,8 @@ def phihrt_pipe(input_json_file): try: data = flat_correction(data,flat,flat_states,rows,cols) - # if out_intermediate: - # data_flatc = data.copy() + if out_intermediate: + data_flatc = data.copy() printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Flat Field correction time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) @@ -487,6 +493,7 @@ def phihrt_pipe(input_json_file): data = prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages) + data_PFc = data.copy() # DC 20211116 printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Prefilter correction time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) @@ -502,7 +509,7 @@ def phihrt_pipe(input_json_file): #----------------- if fs_c: - data, field_stop = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) + data, field_stop, field_stop_ghost = apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) else: @@ -523,6 +530,9 @@ def phihrt_pipe(input_json_file): data,_ = demod_hrt(data, pmp_temp) + if out_intermediate: + data_demod = data.copy() + printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Demodulation time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -543,6 +553,11 @@ def phihrt_pipe(input_json_file): start_time = time.time() + Ic_mask = np.zeros((data_size[0],data_size[1],data_shape[-1]),dtype=bool) + I_c = np.ones(data_shape[-1]) + if limb is not None: + limb_mask = np.zeros((data_size[0],data_size[1],data_shape[-1])) + for scan in range(data_shape[-1]): #I_c = np.mean(data[ceny,cenx,0,cpos_arr[0],int(scan)]) #mean of central 1k x 1k of continuum stokes I @@ -550,35 +565,38 @@ def phihrt_pipe(input_json_file): #I_c = np.mean(data[1500:2000,800:1300,0,cpos_arr[0],int(scan)]) # mean in the not-out-of the Sun south limb #I_c = np.mean(data[350:1700,200:900,0,cpos_arr[0],int(scan)]) # West limb limb_copy = np.copy(data) + #from Daniele Calchetti + if limb is not None: if limb == 'N': - limb_mask, Ic_mask = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = True) + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = True) if limb == 'S': - limb_mask, Ic_mask = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = False) + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'columns', switch = False) if limb == 'W': - limb_mask, Ic_mask = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = True) + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = True) if limb == 'E': - limb_mask, Ic_mask = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = False) + limb_temp, Ic_temp = limb_fitting(data[:,:,0,cpos_arr[0],int(scan)], mode = 'rows', switch = False) - limb_mask = np.where(limb_mask>0,1,0) - Ic_mask = np.where(Ic_mask>0,1,0) + limb_temp = np.where(limb_temp>0,1,0) + Ic_temp = np.where(Ic_temp>0,1,0) - data[:,:,:,:,scan] = data[:,:,:,:,scan] * limb_mask[:,:,np.newaxis,np.newaxis] + data[:,:,:,:,scan] = data[:,:,:,:,scan] * limb_temp[:,:,np.newaxis,np.newaxis] + limb_mask[...,scan] = limb_temp else: - Ic_mask = np.zeros(data_size) - Ic_mask[ceny,cenx] = 1 - Ic_mask = np.where(Ic_mask>0,1,0) + Ic_temp = np.zeros(data_size) + Ic_temp[ceny,cenx] = 1 + Ic_temp = np.where(Ic_temp>0,1,0) if fs_c: - Ic_mask *= field_stop + Ic_temp *= field_stop - Ic_mask = np.array(Ic_mask, dtype=bool) - I_c = np.mean(data[Ic_mask,0,cpos_arr[0],int(scan)]) - data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c + Ic_temp = np.array(Ic_temp, dtype=bool) + I_c[scan] = np.mean(data[Ic_temp,0,cpos_arr[0],int(scan)]) + data[:,:,:,:,scan] = data[:,:,:,:,scan]/I_c[scan] + Ic_mask[...,scan] = Ic_temp + hdr_arr[scan]['CAL_NORM'] = round(I_c[scan],0) # DC 20211116 - # if out_intermediate: - # data_demod = data.copy() printc('--------------------------------------------------------------',bcolors.OKGREEN) printc(f"------------- Stokes Normalising time: {np.round(time.time() - start_time,3)} seconds ",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) @@ -592,7 +610,7 @@ def phihrt_pipe(input_json_file): # CROSS-TALK CALCULATION #----------------- - if CT_ItoQUV: + if ItoQUV: print(" ") printc('-->>>>>>> Cross-talk correction I to Q,U,V ',color=bcolors.OKGREEN) @@ -601,31 +619,32 @@ def phihrt_pipe(input_json_file): num_of_scans = data_shape[-1] - try: - assert ctalk_params.shape == (2,3) - except AssertionError: - print("ctalk_params is not in the required (2,3) shape, please reconcile") - raise AssertionError - - slope, offset = 0, 1 q, u, v = 0, 1, 2 - - for scan_hdr in hdr_arr: + CTparams = np.zeros((2,3,number_of_scans)) + + for scan, scan_hdr in enumerate(hdr_arr): + printc(f' ---- >>>>> CT parameters computation of data scan number: {scan} .... ',color=bcolors.OKGREEN) + if ghost_c: # DC 20211116 + ctalk_params = crosstalk_auto_ItoQUV(data[...,scan],cpos_arr[scan],0,roi=np.asarray(Ic_mask[...,scan]*field_stop_ghost,dtype=bool)) # DC 20211116 + else: # DC 20211116 + ctalk_params = crosstalk_auto_ItoQUV(data[...,scan],cpos_arr[scan],0,roi=Ic_mask[...,scan]) # DC 20211116 + + CTparams[...,scan] = ctalk_params + if 'CAL_CRT0' in scan_hdr: #check to make sure the keywords exist - scan_hdr['CAL_CRT0'] = ctalk_params[slope,q] #I-Q slope - scan_hdr['CAL_CRT2'] = ctalk_params[slope,u] #I-U slope - scan_hdr['CAL_CRT4'] = ctalk_params[slope,v] #I-V slope - - scan_hdr['CAL_CRT1'] = ctalk_params[offset,q] #I-Q offset - scan_hdr['CAL_CRT3'] = ctalk_params[offset,u] #I-U offset - scan_hdr['CAL_CRT5'] = ctalk_params[offset,v] #I-V offset - - ctalk_params = np.repeat(ctalk_params[:,:,np.newaxis], num_of_scans, axis = 2) + + scan_hdr['CAL_CRT0'] = round(ctalk_params[slope,q],4) #I-Q slope + scan_hdr['CAL_CRT2'] = round(ctalk_params[slope,u],4) #I-U slope + scan_hdr['CAL_CRT4'] = round(ctalk_params[slope,v],4) #I-V slope + scan_hdr['CAL_CRT1'] = round(ctalk_params[offset,q],4) #I-Q offset + scan_hdr['CAL_CRT3'] = round(ctalk_params[offset,u],4) #I-U offset + scan_hdr['CAL_CRT5'] = round(ctalk_params[offset,v],4) #I-V offset + + try: + data = CT_ItoQUV(data, CTparams, norm_stokes, cpos_arr, Ic_mask) - try: - data = CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask) except Exception: print("There was an issue applying the I -> Q,U,V cross talk correction") if 'Ic_mask' not in vars(): @@ -656,7 +675,7 @@ def phihrt_pipe(input_json_file): data *= field_stop[rows,cols, np.newaxis, np.newaxis, np.newaxis] # DC change 20211019 only for limb if limb is not None: - data *= limb_mask[rows,cols, np.newaxis, np.newaxis, np.newaxis] + data *= limb_mask[rows,cols, np.newaxis, np.newaxis] else: print(" ") @@ -718,26 +737,36 @@ def phihrt_pipe(input_json_file): hdu_list.writeto(out_dir + scan_name_list[count] + '_reduced.fits', overwrite=True) # DC change 20211014 - """ - if out_intermediate: - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_dark_corrected.fits") - hdu_list[0].data = data_darkc[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_dark_corrected.fits', overwrite=True) - - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") - hdu_list[0].data = data_flatc[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) - - with fits.open(scan) as hdu_list: - print(f"Writing out demod file as: {scan_name_list[count]}_demodulated.fits") - hdu_list[0].data = data_demod[:,:,:,:,count] - hdu_list[0].header = hdr_arr[count] #update the calibration keywords - hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) - """ + + if out_intermediate: # DC 20211116 + if dark_c: # DC 20211116 + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_dark_corrected.fits") + hdu_list[0].data = data_darkc[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_dark_corrected.fits', overwrite=True) + + if flat_c: # DC 20211116 + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") + hdu_list[0].data = data_flatc[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_flat_corrected.fits', overwrite=True) + + if prefilter_f is not None: # DC 20211116 + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_flat_corrected.fits") + hdu_list[0].data = data_PFc[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_prefilter_corrected.fits', overwrite=True) + + if demod: # DC 20211116 + with fits.open(scan) as hdu_list: + print(f"Writing out demod file as: {scan_name_list[count]}_demodulated.fits") + hdu_list[0].data = data_demod[:,:,:,:,count] + hdu_list[0].header = hdr_arr[count] #update the calibration keywords + hdu_list.writeto(out_dir + scan_name_list[count] + '_demodulated.fits', overwrite=True) + # with fits.open(scan) as hdu_list: # hdu_list[0].data = limb_copy @@ -762,8 +791,10 @@ def phihrt_pipe(input_json_file): if limb is not None: - mask = limb_mask*field_stop - + mask = limb_mask*field_stop[...,np.newaxis] + else: + mask = np.ones((data_size[0],data_size[1],data_shape[-1]))*field_stop[...,np.newaxis] + if p_milos: try: @@ -797,7 +828,7 @@ def phihrt_pipe(input_json_file): runtime = dt.strftime("%d_%m_%YT%H_%M_%S") json.dump(input_dict, open(out_dir + f"config_file_{runtime}.json", "w")) - + print(" ") printc('--------------------------------------------------------------',color=bcolors.OKGREEN) printc(f'------------ Reduction Complete: {np.round(time.time() - overall_time,3)} seconds',color=bcolors.OKGREEN) diff --git a/src/hrt_pipe_sub.py b/src/hrt_pipe_sub.py index 3f52a6e..36322c9 100644 --- a/src/hrt_pipe_sub.py +++ b/src/hrt_pipe_sub.py @@ -306,6 +306,7 @@ def flat_correction(data,flat,flat_states,rows,cols) -> np.ndarray: def prefilter_correction(data,voltagesData_arr,prefilter,prefilter_voltages): """ applies prefilter correction + adapted from SPGPylibs """ def _get_v1_index1(x): index1, v1 = min(enumerate([abs(i) for i in x]), key=itemgetter(1)) @@ -349,12 +350,15 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - start_time = time.time() field_stop,_ = load_fits('../field_stop/HRT_field_stop.fits') + field_stop_ghost,_ = load_fits('../field_stop/HRT_field_stop_ghost.fits') field_stop = np.where(field_stop > 0,1,0) + field_stop_ghost = np.where(field_stop_ghost > 0,1,0) if header_imgdirx_exists: if imgdirx_flipped == 'YES': #should be YES for any L1 data, but mistake in processing software field_stop = field_stop[:,::-1] #also need to flip the flat data after dark correction + field_stop_ghost = field_stop_ghost[:,::-1] data *= field_stop[rows,cols,np.newaxis, np.newaxis, np.newaxis] @@ -362,7 +366,85 @@ def apply_field_stop(data, rows, cols, header_imgdirx_exists, imgdirx_flipped) - printc(f"------------- Field stop time: {np.round(time.time() - start_time,3)} seconds",bcolors.OKGREEN) printc('--------------------------------------------------------------',bcolors.OKGREEN) - return data, field_stop + return data, field_stop, field_stop_ghost + +def crosstalk_auto_ItoQUV(data_demod,cpos,wl,roi=np.ones((2048,2048)),verbose=0,npoints=5000,limit=0.2): + import random, statistics + from scipy.optimize import curve_fit + def linear(x,a,b): + return a*x + b + my = [] + sy = [] + + x = data_demod[roi>0,0,cpos].flatten() + ids = np.logical_and(x > limit, x < 1.5) + x = x[ids].flatten() + + N = x.size + idx = random.sample(range(N),npoints) + mx = x[idx].mean() + sx = x[idx].std() + xp = np.linspace(x.min(), x.max(), 100) + + A = np.vstack([x, np.ones(len(x))]).T + + # I to Q + yQ = data_demod[roi>0,1,wl].flatten() + yQ = yQ[ids].flatten() + my.append(yQ[idx].mean()) + sy.append(yQ[idx].std()) + cQ = curve_fit(linear,x,yQ,p0=[0,0])[0] + pQ = np.poly1d(cQ) + + # I to U + yU = data_demod[roi>0,2,wl].flatten() + yU = yU[ids].flatten() + my.append(yU[idx].mean()) + sy.append(yU[idx].std()) + cU = curve_fit(linear,x,yU,p0=[0,0])[0] + pU = np.poly1d(cU) + + # I to V + yV = data_demod[roi>0,3,wl].flatten() + yV = yV[ids].flatten() + my.append(yV[idx].mean()) + sy.append(yV[idx].std()) + cV = curve_fit(linear,x,yV,p0=[0,0])[0] + pV = np.poly1d(cV) + + if verbose: + + PLT_RNG = 3 + fig, ax = plt.subplots(figsize=(8, 8)) + ax.scatter(x[idx],yQ[idx],color='red',alpha=0.6,s=10) + ax.plot(xp, pQ(xp), color='red', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yU[idx],color='blue',alpha=0.6,s=10) + ax.plot(xp, pU(xp), color='blue', linestyle='dashed',linewidth=3.0) + + ax.scatter(x[idx],yV[idx],color='green',alpha=0.6,s=10) + ax.plot(xp, pV(xp), color='green', linestyle='dashed',linewidth=3.0) + + ax.set_xlim([mx - PLT_RNG * sx,mx + PLT_RNG * sx]) + ax.set_ylim([min(my) - 1.8*PLT_RNG * statistics.mean(sy),max(my) + PLT_RNG * statistics.mean(sy)]) + ax.set_xlabel('Stokes I') + ax.set_ylabel('Stokes Q/U/V') + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.4*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4), style='italic',bbox={'facecolor': 'red', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.55*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4), style='italic',bbox={'facecolor': 'blue', 'alpha': 0.1, 'pad': 1}, fontsize=15) + ax.text(mx - 0.9*PLT_RNG * sx, min(my) - 1.7*PLT_RNG * statistics.mean(sy), 'Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4), style='italic',bbox={'facecolor': 'green', 'alpha': 0.1, 'pad': 1}, fontsize=15) +# fig.show() + + print('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4)) + print('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4)) + print('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4)) + +# return cQ,cU,cV, (idx,x,xp,yQ,yU,yV,pQ,pU,pV,mx,sx,my,sy) + else: + printc('Cross-talk from I to Q: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cQ[0],cQ[1],width=8,prec=4),color=bcolors.OKGREEN) + printc('Cross-talk from I to U: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cU[0],cU[1],width=8,prec=4),color=bcolors.OKGREEN) + printc('Cross-talk from I to V: slope = {: {width}.{prec}f} ; off-set = {: {width}.{prec}f} '.format(cV[0],cV[1],width=8,prec=4),color=bcolors.OKGREEN) + ct = np.asarray((cQ,cU,cV)).T + return ct def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): """ @@ -374,13 +456,18 @@ def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): # ceny = slice(data_shape[0]//2 - data_shape[0]//4, data_shape[0]//2 + data_shape[0]//4) # cenx = slice(data_shape[1]//2 - data_shape[1]//4, data_shape[1]//2 + data_shape[1]//4) - cont_stokes = np.mean(data[Ic_mask,0,cpos_arr[0],:], axis = 0) + cont_stokes = np.ones(data_shape[-1]) + + for scan in range(data_shape[-1]): + cont_stokes[scan] = np.mean(data[Ic_mask[...,scan],0,cpos_arr[0],scan]) for i in range(6): # stokes_i_wv_avg = np.mean(data[ceny,cenx,0,i,:], axis = (0,1)) - stokes_i_wv_avg = np.mean(data[Ic_mask,0,i,:], axis = 0) - + stokes_i_wv_avg = np.ones(data_shape[-1]) + for scan in range(data_shape[-1]): + stokes_i_wv_avg[scan] = np.mean(data[Ic_mask[...,scan],0,i,scan]) + if norm_stokes: #if normed, applies normalised offset to normed stokes @@ -399,7 +486,7 @@ def CT_ItoQUV(data, ctalk_params, norm_stokes, cpos_arr, Ic_mask): data[:,:,2,i,:] = before_ctalk_data[:,:,2,i,:] - before_ctalk_data[:,:,0,i,:]*u_slope - u_int data[:,:,3,i,:] = before_ctalk_data[:,:,3,i,:] - before_ctalk_data[:,:,0,i,:]*v_slope - v_int - + else: #if not normed, applies raw offset cross talk correction to raw stokes counts @@ -432,7 +519,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field try: CMILOS_LOC = os.path.realpath(__file__) - CMILOS_LOC = CMILOS_LOC[:-19] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters + CMILOS_LOC = CMILOS_LOC.split('src/')[0] + 'cmilos/' #-11 as hrt_pipe.py is 11 characters if os.path.isfile(CMILOS_LOC+'milos'): printc("Cmilos executable located at:", CMILOS_LOC,color=bcolors.WARNING) @@ -569,7 +656,7 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field rte_data_products[4,:,:] = rte_invs_noth[8,:,:] #vlos rte_data_products[5,:,:] = rte_invs_noth[2,:,:]*np.cos(rte_invs_noth[3,:,:]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1]] #field stop, set outside to 0 + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) @@ -585,37 +672,37 @@ def cmilos(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, field print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header= hdr hdu_list[0].data = rte_data_products[5,:,:] hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) # DC change 20211101 Gherdardo needs separate fits files from inversion with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[3,:,:] hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[2,:,:] hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[1,:,:] hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[4,:,:] hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[0,:,:] hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) @@ -634,7 +721,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, try: CMILOS_LOC = os.path.realpath(__file__) - CMILOS_LOC = CMILOS_LOC[:-19] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters + CMILOS_LOC = CMILOS_LOC.split('src/')[0] + 'cmilos-fits/' #-11 as hrt_pipe.py is 11 characters if os.path.isfile(CMILOS_LOC+'milos'): printc("Cmilos-fits executable located at:", CMILOS_LOC,color=bcolors.WARNING) @@ -655,7 +742,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, file_path = data_f[scan] wave_axis = wve_axis_arr[scan] - hdr = hdr_arr[scan] + hdr_scan = hdr_arr[scan] # DC 20211117 #must invert each scan independently, as cmilos only takes in one dataset at a time @@ -792,7 +879,7 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, rte_data_products[4,:,:] = rte_out[7,:,:] #vlos rte_data_products[5,:,:] = rte_out[1,:,:]*np.cos(rte_out[2,:,:]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1]] #field stop, set outside to 0 + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 if out_rte_filename is None: filename_root = str(file_path.split('.fits')[0][-10:]) @@ -808,37 +895,37 @@ def cmilos_fits(data_f, hdr_arr, wve_axis_arr, data_shape, cpos_arr, data, rte, print(f"out_rte_filename neither string nor list, reverting to default: {filename_root}") with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[5,:,:] hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) # DC change 20211101 Gherdardo needs separate fits files from inversion with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[3,:,:] hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[2,:,:] hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[1,:,:] hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[4,:,:] hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr_scan # DC 20211117 hdu_list[0].data = rte_data_products[0,:,:] hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) @@ -858,7 +945,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st try: PMILOS_LOC = os.path.realpath(__file__) - PMILOS_LOC = PMILOS_LOC[:-19] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py + PMILOS_LOC = PMILOS_LOC[:-15] + 'p-milos/' #11 as hrt_pipe.py is 11 characters -8 if in utils.py if os.path.isfile(PMILOS_LOC+'pmilos.x'): printc("Pmilos executable located at:", PMILOS_LOC,color=bcolors.WARNING) @@ -987,7 +1074,7 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st rte_data_products[4,:,:] = result[:,:,2] #vlos rte_data_products[5,:,:] = result[:,:,1]*np.cos(result[:,:,5]*np.pi/180.) #blos - rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1]] #field stop, set outside to 0 + rte_data_products *= field_stop[np.newaxis,start_row:start_row + data.shape[0],start_col:start_col + data.shape[1],scan] #field stop, set outside to 0 #flipping taken care of for the field stop in the hrt_pipe #printc(f' ---- >>>>> and HERE now .... ',color=bcolors.WARNING) @@ -997,37 +1084,37 @@ def pmilos(data_f, wve_axis_arr, data_shape, cpos_arr, data, rte, field_stop, st filename_root = out_rte_filename with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products hdu_list.writeto(out_dir+filename_root+'_rte_data_products.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[5,:,:] hdu_list.writeto(out_dir+filename_root+'_blos_rte.fits', overwrite=True) # DC change 20211101 Gherdardo needs separate fits files from inversion with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[3,:,:] hdu_list.writeto(out_dir+filename_root+'_bazi_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[2,:,:] hdu_list.writeto(out_dir+filename_root+'_binc_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[1,:,:] hdu_list.writeto(out_dir+filename_root+'_bmag_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[4,:,:] hdu_list.writeto(out_dir+filename_root+'_vlos_rte.fits', overwrite=True) with fits.open(file_path) as hdu_list: - hdu_list[0].hdr = hdr + hdu_list[0].header = hdr hdu_list[0].data = rte_data_products[0,:,:] hdu_list.writeto(out_dir+filename_root+'_Icont_rte.fits', overwrite=True) -- GitLab From ebae68e7d463392fe19c8a6d1e99f906c09f9e98 Mon Sep 17 00:00:00 2001 From: jonas Date: Thu, 18 Nov 2021 15:23:42 +0100 Subject: [PATCH 12/34] rm files --- cmilos-fits/calculosCompartidos.o | Bin 14648 -> 0 bytes cmilos-fits/create_cuantic.o | Bin 6016 -> 0 bytes cmilos-fits/fgauss.o | Bin 3824 -> 0 bytes cmilos-fits/fits.o | Bin 10944 -> 0 bytes cmilos-fits/fvoigt.o | Bin 4144 -> 0 bytes cmilos-fits/lib.o | Bin 13464 -> 0 bytes cmilos-fits/me_der.o | Bin 40480 -> 0 bytes cmilos-fits/mil_sinrf.o | Bin 15984 -> 0 bytes cmilos-fits/milos.o | Bin 66864 -> 0 bytes cmilos/calculosCompartidos.o | Bin 14648 -> 0 bytes cmilos/create_cuantic.o | Bin 6016 -> 0 bytes cmilos/fgauss.o | Bin 3824 -> 0 bytes cmilos/fvoigt.o | Bin 4144 -> 0 bytes cmilos/lib.o | Bin 13464 -> 0 bytes cmilos/me_der.o | Bin 40480 -> 0 bytes cmilos/mil_sinrf.o | Bin 15984 -> 0 bytes cmilos/milos.o | Bin 61744 -> 0 bytes hrt_pipe.py | 817 --------------------- hrt_pipe_sub.py | 1121 ----------------------------- 19 files changed, 1938 deletions(-) delete mode 100644 cmilos-fits/calculosCompartidos.o delete mode 100644 cmilos-fits/create_cuantic.o delete mode 100644 cmilos-fits/fgauss.o delete mode 100644 cmilos-fits/fits.o delete mode 100644 cmilos-fits/fvoigt.o delete mode 100644 cmilos-fits/lib.o delete mode 100644 cmilos-fits/me_der.o delete mode 100644 cmilos-fits/mil_sinrf.o delete mode 100644 cmilos-fits/milos.o delete mode 100644 cmilos/calculosCompartidos.o delete mode 100644 cmilos/create_cuantic.o delete mode 100644 cmilos/fgauss.o delete mode 100644 cmilos/fvoigt.o delete mode 100644 cmilos/lib.o delete mode 100644 cmilos/me_der.o delete mode 100644 cmilos/mil_sinrf.o delete mode 100644 cmilos/milos.o delete mode 100644 hrt_pipe.py delete mode 100644 hrt_pipe_sub.py diff --git a/cmilos-fits/calculosCompartidos.o b/cmilos-fits/calculosCompartidos.o deleted file mode 100644 index 7a2c59611575655749f93e96db2437d6898e3ef3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14648 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 TPidA-f5h}ZmeDi@cK!bV(4cNH diff --git a/cmilos-fits/fgauss.o b/cmilos-fits/fgauss.o deleted file mode 100644 index a468fbe1dbae07db2291b511df58c05bd78d91d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3824 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 diff --git a/cmilos-fits/lib.o b/cmilos-fits/lib.o deleted file mode 100644 index 734d22241eeea6f356e24c58ca6ab86442bf967b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13464 zcmeHOeRNdEb$?GQ7Nuza?%S)mKN&Bl@bS`R?jy;*4RwQEg<;Z!*lZzx-Ej5E*R``yZj&jQNeQ z8TPwlXstX$48m>b8rI?q)Gr^X0|EnpcZPR|ew5{^Hqn)o5Mgsj<=fxG)!Wo2>q_kNhE3El5qH0%QkR;5S zsb@RYl&+PAXDg`YteWXgX=}Su+L|78XS!zKcW!uw+sJl#Bf*y&4u;it!a;~j|2Y^g zq@}J@uNa9jn3Nd0P7!3Fxz=@xtLz#jvz3zuUT6fn&6;bN$1pm`tgB3A+jAs{F9M| z$H90#hEYhKg{}`y1nuJ1&j+yaVHN&qsB7U`_$e{6_xim)t#v0YV*D8N!ej36yV(JN zCTJQ~wb!`s3YkiKsKdDLDr-H^IjwIT?c``kd!T39#p@>~C@VW+`G_w$cRdA~s4srn0 zoW&eggS~w?d#g$~>w$6BlDuj!2`rgJU=@v4!Q00ra%2LLK8GmI6^fMFXxLA55o6)jbM-VP-n<}Olx@(qed@_i+U}P(vp7w@Tq}Ua7x{u=?W0|ZS-Z&oM(`-y&In#1ADng>gX9uM z@coeXP%k35u07Bho^}k>w9nTQ0eRa82tqBFwbmOc9K%x$vs3slg?(H=u!KG;RzZ#X zcJNiOj+?K7b=vtVMxj;aXJ^aD#>NoV4xRn!W!5-y_LFD?1_NV})_$$!y3w(*uzB$8 zkKY*^Yd5m{H|?WL;aNkIK*hLdZVMl*ll~kLrYNL;&vj#Td_|OP`{05U)Ts0cN zgjZ}P<{OMWJ35vb!i#}*V&+RY7hXCN-RyP2&_Ktzv+a0q+@i0xwSWR8;o#Bqyc`Xt zl>|DRXNht}!+bAn_G*t^Vd~Mt!=;-i=txXfy)08~rRAAj zx)t^#Z38`Bq|wA%c&Hq3(^%(g$i+vHh(=mZH!Y7QdScf6&Opa_zS}y~v>|4#x(1=K z^dRNP*q?%^I*h$o<2r;)R}BXb!Sa30zk%Zv6=2WYMsPIKt7i|WhB~aPzm5bCWPU(O zu8f&TH20Ut@q$?AP5#?+ox&gfXs_SXUbn!bYzNa?|CM$ahOdAxz+vz#Yslt*_BLhTcQ73Zn3dXs|ESo$Xd*>Y(~|ICv@ZBiqTDFX-zW$Hc}1 z9RNwlxt}=>aH^fX&dqml7FL^Yv*S=ruKzSUVXYUMzHF@?izS|png4A+GdmDoPBKqV zoHVc~__J@BwMe1&=YlX@PF~kB+?OgGaEhUx3La`cPx{8xXW~$KfSqB72LJE!5kI2l z`}*ow;&pwMZXSjis_}UMp(J}5na90&f+gN(hKXvC_qbWKJuko&baNqUO%3htR?feNEt^MgQB3lUbGyf>6ptn3(x`JNvu?j??Ibr%`xiL_@Jqp;6E%%0|BHn;{8rsMj=WKUd5KX2AVIN`*++6jD-8cC=)eG!<@4D%(>mRzqAfE-DXvS z->v=lun_3S4aN=(xfvF&1UgzrqP;HiIOKh^G`MhQ({;HE5uvgG*IGTbW(?Qk}_ujsxoPtljD_h`T0V%Hb3*B*PGb{&^Mk&(dF^CH`8I3sI|Z8PoNiK zym=glp7yUs)uC}*eNGSdk;(;`*Xd&e`@VqB3P%v=!|F&l_?yi4rClKXZ)qK&aKtp% z_OwB&Zl2W5i$>!0i1yeK-HMD+UO)zonO!k!k$o?jR|6yQL_a=f6-IEZjkq;`PSkup zY7W@@06X_bdub8)w)PCO@?6p%_MOV?d(2i=$y{LJ2MWi7&u03vJ-C%#M-CAVz9wQ2 zi!|InT1TKsN7HBMH(%B)~r$D>OioIUB`&O#j#J~q;$i#UbXMzn0iuIPwBz8 z#mYtWC2slje}C>MllOu3@caeeNW-H7GP9u)<2j6xLF4FZy;jkCMtL zK9D^{`3p1Fh0OhvCM|hWcAq)UvDAHFug*_b@gI9bxn%EyV&%!4VmvJN!&jy>m2Jfa^#lG*c z|LlFShQBZ9v>b0fgNMXGRK19_ws_XFZ~~;Y&oy`9nuyaib0YXgX7BHsusq?2;O%+q z`{9SK?;d-7gCDX!B0TYo9AY6SX8tKl=17ZNX;3~@mqNELnf!V(k*;s>eZd!LXh3~O(pS4J z*^tgO)GqWT8-3gA8#iyPOZx82Bz?&`Uutt=Q?jAnx3%7v+`hRnU0cSOPWMgc^OIYB zTQYU&Ew$-}&D*2l7*QtbH*ZaBz5_#BYZJb^d|NlBu1E2el}+a=O)`Idx}kP!BUDIE z%qAhRQ9hDS_#+uDt*ZKhue5q~b;K9jyfw4^2H&Exin7nyiq7Kts(0V4sN22jyrQY@ zcKXLC;Pd&|s*j;j>G9rQV0cRQ6h=Hg%N6mI?!G4MDc?C|siz`4HSF1|7G6JXx~F1^ zr(E}xR(gDuo)XNd^tg4J?#Evp=l3nDBOdS0f~B64Y+=FIrhB})#~mR$`tssz9FSvcW#|K0g+&6%%k7!X!=^GZ)74r8KLJ!MTNxJH!t4_Ku z@vN+dqE!I?8g~S`>|4IhgoNQ0!Y5KuB_7p@sB^Iq?w+nXNN$bc?DcC#R zQwn?7HeO0LUhYJ~%<83J@e=2k;rwPXeoFk=ey;GWEcm;LxYK8_ zmpC7KLfiHXkJ~exv*&jl=7h^C3h6bU{iBqk1Zgfx2!G`qJ4C?Ev_Cn1j{UiRdN(-s zV22Ll7##6EO{Y>tQKX7{9WWGrJ>NvlF59jxfzY9OwpI>r*e@6UJ$cG0w z_8kJCGmjlr%-?tA{GEm;Dzqgo<>J^xV}%p`7YT||i2qGg3c*P(_(BgZIo!uD42|QW z@8jo|<`*jL`#UxBN}rK&~yAdoL;Hh zys<2y=qt+>efIO8Qz}c;Dgm35gk0e~^|CofAbNZ7Ur*)D3^Ev*ygx|sOVF|C}_*8Ca z!RJwqmq_?q9QR51yBv>5_(G1~CgEw0CnWq{j^8EWzvOtEguA$%ACT}Ojz1~ki#eZT z65hh`XC!<#$1h0uVUCYU_$)4WD!<}{J?C@$MhTB`K3|gX2RXh}!XM`N?GpY1$Ll5B z&*gqY!WVMypud;nL5Y4p?=O*XaV~C?@Ws3@>>>EKaQrTb{xI+FlyKqy-;?k#?>{Qx zyLtaf2|vO6JrXX?(U644c>lbFKgj!+CHw{6pThl7tXG_uc@n;g(~EN>=pW{IP@+H0 z@g)*2=D)*nBFoEGc^*gni}5G!so4(PdEYJOxZp$csDvH#lyV6^Uvc1+atVB+gO4-Y z{%Z$4rCfr3r$ldHj7r-i^hX`IQ~&?q`6=m7as{7XaGciTl>5E|ck(fL-YWCi!*Q8U zzXNyjiSm4w=$-gWli-JWJ}c8V@;p?=|C#5ZGX4dgZwmc)K|Yl)ah&L#c9_HSO+hd6 z)Oj42>F;vj&UL-!z@2%KkA$NTANmtz8*d0)yo0_g;o=>1Si;3Sr5t%P6~RZmQy!FX z@lH7{;o_a*<;n>@;+?Ws!o@p<{*yJQ+;YBu4@>x7j-Qrr@lNqM@+cw^@03LnF5W5I zC0x8y4okRrr#SN~;xFDQ+Z_1@;o_arA>rbkazes4@cmZG8t>YYuHA?_-C)<7M5`fL zS6h}&Zci&^chsh9m9mYEjY?TVJ#~mYP!`DVRw!kO`Yl_MTQOs6eL7jTbj9i$@##77 zH=rYC$xZ814Yga6Wcfd=_%NMZLH<$@0!C$6tk3R#;O#vRIGH5G$3oIjdj{4RVh)_jG$!T4ZP78r5ZG;selm#i$KGGbe9Tk zhCgp{EZh2PsY|zZf41vyf4X)1qg%J-(@lbqfC>r7AE6bhuFcr0h*bj=^80?zy>I3w zWGwd64xh}t_r2%cckVgoo_p@O_dQm|-Km3u!GQk>25t!C&U`cwc-5#4!<86!8x{a^6-tT7I=IwR9{)dgI#7jn;UloG*xK->%%JAI~8SQuvMV?UD zJ(0q0RwXpJG~u=PId{Bma=!YoDr`O(1Wy5L%>p3JCkNrAy3krP zPtFQ>7Pi*hBWEF=jkeazlC!})E3?)#;EadmzZ!!3ME53d^p1F)6$iW%U748I5f8Q` zFPm$XcR1^7BjLGL$qpx7(pK5h+!Az}+W=JDcr4n{bj%KJx1;UJ^Mxs=@qJVoI%cnL zh&b`phpmSLxXXHJVS4<9@yZt0TM((5Yg^@e`SrZl?xi9rh+EM(jR)q&t&%Cah3Z)iB;(G7oYH=g8-1PkLdN(rO^`4Au zB%|w}l(qzSI*og3(hK&Xflo%NQG>mHLBvfo?sI~jFzW)xYjX-7(e1X`i8>wck;p7i zPEOZW1Zny-d{h(NYE9khw7yc{6l{qc1pySkf;D>GE~+3B>~J=!TJ1=kQ;^cSc_dPX zLI?Cm!5iok-oCUQ9OM=#F4aZkumj}@Z<}90s0UDu_d>!ukqDl4)^E{@crvmM1y1m7 z_Tep&(YV2X<1b*{a>^}uT=BOeQs{b*N9uq>;S*i&x1yvIF>j}BO*`NgY!W&OncUlG z_;UQlypvsTyU<%0CoXzRd5!m8mKZpFM@{;!aE%9p+Z5S=)0lS(Tr9=~@!(-{$qM6E zeCu)B3SR+&K%%k3hRxWluqwE#AQ>6YUiN90p-YvY=GS|KE+T~93OoP6S)YVbG=ok% zG$e(%R~2pm3S}`c2SDQp1>Y8HL`Rs;Q(RxiRxofbRm$Kzn)3G3k*=kw;uBhyRK zv0jZU;MT$=T@DyVpMmTABONPyjy3hU=2HdM+DMVmz-dN4|Jh%hjbyn&}C`_RLP+!|`OcxD-H$HiDx+HLOx@f2i zSw8~;cJQb1TNCVYVG=x~^K7Zy1DD-fxdSZ-7hTZY8sx#{#dBj;se3^oe#%3mc(S0l zaIRIi1Bdl3bFKOp=2{J{_-zL;A{55=C_7w8hd%+FHT?%PQOEo6*0JF8Q81nSY)#{9 z$0u9i&{2HXkAGd-jHA%+(BNYbTzVO=Q92UhR-8N3 z73-(c8i3Td;Rf+=^pKSb(Q5Ol=_e3{s0rGEma>|mrlJ1T;J z0*jzZEs4oivHd?Vwl?o2xM#TQHzvV;r|y;R^rJ%EolXQ}&*<)it_e#-D1)$ND+C!x zejc|(FFH{WdwP&jP+homBum1vrwdFt9DOc%U(9>S+Zn6C2)DcIZTQT1a8L3Yh(T(1 z(&IZTchJzwL!}fP?gok7)rQz4R7#tTo@ja{9_)-qyOI~zG@^H_nCixK36D)K2GO<5 zt4TK&HlG?=ZGE@Bdfkdhl^cEC`gW^3VN>KWw8r{&TVa=#x)!aiPW4);u{f~dcFN+b z_atlJvZ|>|D(GXnzm-6zCDd+d?I@UFI8=(RwR5gjYL~)d+0jN28iiBMZtH}GNLlhT ztfYWma5@_0cZQ+#`HUK%A9$$Zq0OfTd55gELx$1~u0V{5tA-*JjQv6>pYJ7?5FT%^-~M!XgTnM2!Uqt5L*1d;Ua{C`zsE_&}&yj%41y_C?VL3axl8R8XDxm5NZ9ZMLI3 zns#vji3N{G5sf6Tnw%~fAzaop?t$Y7hYl3fM#l4w2gxKI%YK9kh(-^9W5&Iryjf0q zd6=Zkax)2 zAFJ3C_c~);-L}`R)#>n>S%x~D;0I3dE$UJAD``92(pEH{eySogO6jh(=@29c-JOU< zPbRO%v72j=3Y(!$tEO=Wbx7UWFCgro^7ex}QC^MeWYJ9$ZCT%uPBs}*S%n@LK!3v_ z#9Frc{p57~_U&X=xOODHEPP{W?Z`s*0Nu%;Lcf=BC@Y0dv;FLyreF2xXPYIqqZG;@ z1yJ764q2izDEXmTh0VQ#ypz`2FBbTH%?iiS>o!XO*Qd|nD(OZ`FM=rIx|dCZ;A+-U;b2S{1K| zDeuUDati2Q=w3=$Hnk@mjQSc$7omC>bjC6&ZKQIJyB_!j*tg*%3X>I-CPPhXfFUVF z4VPFS8t1G}N!SW811t_G-4%E}*4hUZo$hZc_-yWxz{v8)tz36XPM|T}B6>j?2Or8CA!1-LN|D# zvV~nP*xZJptke!NN~?dCT@I07MQDiA+!BtSY&xt*v@7AnjNYcE19q?l16={8!*HGT zp>|Ar(jgeL5{A=^;67O6y^2dmN9~AXee)mx*xSp=I{4u<-1T~c2R#uHkaa+eQ%=48 z({8j4@xa^a7g7$Zqpv@^5mXWd-1((gL+nejyJ9o9S{JV(J*s5nzq-X*T{{Sd(Sn3P z=FpkmUcdYynH;U&VXZD_`JQ;?p3HCllq=sNv%%H9*6Kf@9+vOOeCAZP+{R>J6$;|4 zVV9=Zley{yDQw($kG1+~!aI25AAHc;J6GW#|3^*!TIPcHO}r_K-v&`BdQM1YRqoj! z?&g5g+={`yKGX@Hh(WI|)&s+f^+flsJd!CsiEGAM7pK^KSgRYE$ACqj^ZEi_PM5Qt z))Yc*{VF+>De2MtyI!Vp59UWO6ZF;(yYJxBxbFr`;T64kpKah(u0H!dB1y=JaZqMA zs?d5_-Lmvv^y2q3hu-Y%{S^cf$UM&@=qQkB;}Lp&AoC25LOl9+9?^<2kK;&XWH2?) zC31c65jSc=Z+T=e~&Ju2v}8l9}?!m z$`anQ0y2Ut(>1BgVGiM?abI!+YqT@SlL)9X+B*{$e7N#zz` z3U$z0yAv}QP%(rUAHg8x$9oi2xD?khwq=csLK-@yX_001yri(XXOM(`;oD)UydXzB zm55Lyx>)u(l7}S_4Bs9;iJ2;MchrPB~#n!lY5FujRYmWyp)A>3|n1$Fa zsR(H|a&(xtGEIwk1Oqj54vF;mQY1UWZtxXRSBV8(fQQgS%F2o)Wq?9^RU3I`+rq2ezE zmNl}9sj!anL%uTV;a1f}S}BtEiSa~TRk-X5xk~9n$U8+ppkV)K0SmFLN@j>gUdyYI zf7BXzVIYmvq)SRgAxbq?xfmmY3~1&Jtr_rs1mZ6bod+Fd)g$vW=tVV!dV~EdedX8C zPqc=j{WJufTuzl8C3Dcp+DiK zp&mOu=KB<^cgVJWvPts4XtuR>a-q^SJS!vjMB`S+YsIA4fl0vk*SAXa!76qy`yv~N z;X0PSDTo=EL?a}@G6#a*7g)U_6r+$OvjPcJNQ4r5s5S~zEn!O*N7663k}~OxRdngN zy%(M^StDs?hH-^Z8_lB&k_kEKqArY-dl1P7TPs_nU*(g}Ny_I;JbEH|Q7j$0O2$gG zlx+$9(b=eZ2(_<191}g;UZ;%(2j=(@u*ahq7}Verv!=GkntMaGcM?v3_Fw-eYi$PU z4XGP}1y25{n+NQX8R^I5J9xU?r(HlY%XCFaaG+!HR?_#%_rC07VS(zWE_y-ZoeA zetk{xB)j2$cEiY7lD30%%YEblc~QzPGB}N$!U~Me0aQPRHxpzQs2S>UG?km%jGZe=tbK*)AbhJ^lSV& zoSt|MfA_$Aw9~2Fq2|koyeM4Cpp?NEXUZWNKwrdh9U?J!Amlyaid1(*Vsn(OW0iNB zeql#@lh-(u4gHe(6jVd7`ci=or%VFu_5ui z)C|zaWeJ=MO)I#x2WiYohwj7_b(1VVV9JU4Cpv5KLy^ZIGaPJ|OdKQ$h-m{|(H6bF z*3ObtWED$L+dPT-m|0y6+h%rT1@)o`&;WHAdje2ZVceQ}fPDd_`d%z~3>5-V{6eaV zKWpt%lEmSn7w4@^xk0=f?8PmFK9JtB><&Tyym$G$(4m^MoXbcl>F-h3Q; z4IK#2cBAKF(e5r}%@DkyF?~D#FWLF8LFX@6VRrsl@KjCXVTiwP&xdPZ*AF8=D-Io$ z-r?ZFd2A=djTl6_CJX$T><1c|=udWkmnF#&tGO#C!m8}+&vrnkXXl8Jw?TsDRZQh2 z*)SA|A(d|t{6!ys7E^njw?QK5TR!|F$?~j1&8P<%A|@LUKd>r^9x|69Rp8f$@&&xG zrLs5Eo6Gm$_FvL49EZf1nIp(N_<0bN&yaE^p6<@(gUEJ47Jmkb3w0l7eMtoVJe&VP zoh5Au0qJv#OWO2QHIwOhhqtJf;ia4dfS(^iU?<+1$?`6A+3Yp{llkef-d-U^z6SNW zLbr=5MK1gf?iP9;C-s6C7y0+vm-&pO+fo!0ny>i8_5OWuJwll~_Tu^%d40*V=56<9 zeh(?1J&6~+W?p0drZW>kYrHnLC)0#X4SaZ}0wT7(p3LQtB`C&1a<;c;LuMT^PB_Rc zMCQip+>n_~(dFcY{aM}zvF7%1DuHu4R-5o%oN=4e{0Fu73fr#yZC04-3?3v7OL&nZ zq+}$7QdZ}^;donJ?=9E+z+R_q(|Z|bvF)L;GljcbB{=&Zk0!ZuQo(Q;6~uo`BBIal}^ILFJ6;^0BX5SwLX2__{IDF9n!*9VH1Aw~#4SSB<_ zadRo-(iIM{^#=V(#1vosn)PtaP3+A394tR$H_S62;#gDVF|PFP3*MzA-&!o5DBALI%$N$3N#v2Q(=L z=QN%P?hm%bSHDS#l=mrlpQ=ZERs~{plg4AD>L3F?gmW$p<9r|M_jZzkdDLIxFA%eC z`Ay7w6HpkZUBAac9S(wrt@vIX{~9FN-G$re%~&Z}=FG;)5Tyfh-=2__rOp_zrNka^ zR9{`kRR>DW2@XbS_J=`bt5Yyiu!8f=B1MSH<}rrzgk*J#;|Y*1NADiH=E_m4U2MVFjQ!38_8pQpi+wdU_{0ArH5Zew7@`BhYMxR_ndM464b zIF|BvBoh+*VL-?5SF#5j6b(|-rw}sKrS2eP>q;@>SD}(x!e{Cl5UaPNnWpFL2}r>w zKjmP?A?t|b02PHk;mBn1t`>~K0E%HUT8YX;$uFmbdDvWsmdYe>B@VJ%5B_TWUaa{A z2j|Z0tbEKq=QG=e1IqTVDcT&Xv(BB>>U^voo2cdbI~*WvEyIS6zkyV%&z;qI`B)w4 zvs&~wWp&=Uv#OVa&hAv#P0&)U#KGTAs*BHwRb>B=g6S{Stvb6h=sL~niD;HpH|qu* z535;yJptCyeNQl?k0(IED0@hMPmnWLXFzTNYCj-9I2C_D4tf|nx40N8=tMXqafBw= zsV0ryR&E=p;@}5gM<0pw1NODTL%LpT!g~p)+ntJxQ-OVs_4^appN_rbWkTQXrW?i; zIu)&s2a+~kg#J{lcxlcQa`SW{Z>Ra=)@g47==I%lq zUnIxiY8?)6^FMIjiZzk??cfYKYdUgisO>!&X(0^&8GsYsZ$PH*v3`>Zmzv)|o%KhY zig(m14E>O`h(?@H0JxS|p&uuVljPy@DPj>h_etn*`Di|vhAVTY!M5DDx4`U-RCjD)IxHMBYxd&|XD_o5)?ut}R24M$^6D;Oey*7oqsYIssB%+;5 z*E#8F;Y2zScB38G-{eGhV;CE@Gm*X#NT>Ck7L9bIuq3-~Jc6(0UOdY2AdYkgyb~K6 zTF@9~-@%dEBm(}znC>$j7-VCLhC+0uNc_>tG16g$jj3qawbg;t0LraVC}4NOQti*x za5o)h_ynrPoyuvN)xr0I$ACQsOm>g7rE9U@2nda|K<)i!+7LI#KD;*}j1abpaks1< z9D_#^!Iu)j!-?RbMDRDw3$W1z4+NB3tFOh>Gdpy;=-2BXQ9U5LndeEd8EOF0=+=bS z!p@rUgS1L=367(l?~{aHI`sM%IG3J|Pwq6blN71q~4k!pK{=r9e4 z-p(+fx3E7t5qu*N%p`)phXE}QA|!(WJpcoOyu|rH8MsIe@e8L?kAMXcJ~xot4U2+NHae&5=zYr%rDeAr`bgHm5=GwDeFkrnXR&+&~+ON+-PzhqX6A{H5-7_-?=wES}fUJrsqb06Wd?;dr#W z>6fa9!m}ggAnx64Xq0{L2519oKYnYINcUnFcedBC0qOhDh@EVN6MYK}t1jGarE0I# zin$2~*?sU-%|7hPM+Q{IUgznqz&#-DdF0y0?hnIsP%sLR+VAnUZ#sy*u+}dd=J*tv zHu=l11fvzObZh|SmL_3TMBJadG<=?zO$rCuNg}y>@vq7qc*t@WA$OO6yGzKoql{Wv ziB81P$GGX+!)|mt4aDVxQr~Wi59@N%cK~cx#-qW`cnXu;|20l_LYHH8;U93Aoj=}< zro0MEK_(iaRuA9|iE+w{K?l3CCPUCeINpSdf;_<}_) zj*0O9Q%3VSZYUEKpeeeM9MDQpX+vm~HXHbb;vlsFzq45~O0e6J>>2n~p(GRpVn&dH zJJAkhN-z7SwC3|#Szp6}o^(=GuWD7jMvqx&8d4!zp$!So2r2hDup#+ANF1ZuU&@X} zA4IFqvJVfS*l*qp4$V`_hPKZj^Jo@%jDm*Bugp!;jI7EilM|9ypKNEDBACk7g;cqaeHa<4n`@ z7r0%jSe;C)@muaq#;D7>FT<;LB5B235 z0R?kEYQXBx^>cp#*WfM7bqTqKH5Z4SW|h;N#aLr8RRe&j{`&szO}cwZ%wwdx9Gwz7cN66 z5uO_61+taBK3jxvq}xh8Oh&yoxKj!Y9N+_4r?^q*3*0D#OCOS(<1y;tR3@jkGLG>H zEzF4ZzV`AAYzM>JUEP?GTu$3rpf?U3c;H|>crcC!(aY7dT51hIV(9G@GHYbJgkh{u zUf#l%uL7zz^Lj@_mi`F^+JVA;AST#nA_T{f`mxqtib03Wu^f_Nl6kW*1J(Gux44yJ$TAFOYD=f=SF4|b5xy9k z)h-~c_NvuSp}kF2I#?$<_&s%iJ(`DNU2oXlUg%&t1;o2i7nOTl*{_DD3aAMRK|NY9 zL~U%vxWHI61l#Dd_#KPxdEj91h#ftgyj1qBsVc#W>|Co4_3$pN4h-=`g_q5z2f1pL zbJu@b$qUIif1(E|u~!(UJrt?Vpkh9cNJHvjs%M-S_BM zU{G3Mt?82X>gLEsuZ7UEYRn+jm^%?z_G!&c0#H(@&u>m6z+8L&Ud}$WK}p%ga~s_C zM{Ck;QuTDOPd-$mrr;>sswsuy5jw!W?fu?stJsP)p;h1(3q_cz1rOtUxs^IZ#b>up zVQ#@0KO5yD9G%Xm)Ey_?FgSo|^bjVKXx-SbF$C*im{xDr%Pb8T9oX(faH~YHd@aH( zCx~p+<1(p)$0F;c`E7KYM|OE>0Ta~B~u_QvC@ zat~hJ!534UW(8H^tJqOsGGq9~=dQVFv$VmV7X!Q;xfHy@!YW&R_3r`kaFBK}^-3qbwLF++qe1 zT)v$`q6isjwUB_yr@Uy@_+!6};7YOTI_z=?PsB5Z<$ojs%O0SMVqR8ULYj}%M@!@$ zH0UBZVlNE|$GV&HM1ob<|52f;T0hsTZ&=Ca8flBTGewQlqiB+U6)X$(rY=QMHTnma ztaY8d)+ByJvR2d5wQquo^D__}%vJ7hBv9_L1`BT5%fh8TfqLRzSC%ogwQWjz%msW~ zL^UeWEb*NT(^+TZDLUA4zJMZ(wNn?BlmoYedqGhotErnK4jFF5E{RQ&KV$xS7K(6M zLJBC5r!Iau?CO@*q%jtt+HUZ~4lYedk3lUkD!+<^?1X4QpYtoh6%H#w<_TM==fQlCXEEUpz_#~x z*V_L{XD&WNs zIlC;LpMp}YhpkeI?;&x~alCH_LqGszmA&jgRo2C}vRFEMKOCf!FFGM6i^KXNL{nH9 z$%5tZvN_Df(+?ymCEYO7*{`KbonC5^HAKA?^q}eA& zVKyhnAj4td?exk=sXinNPY_!hsUO`#;<8Lqn#};DAgNBN*Bx1@ z+sb%*dSE;+Ttx;P%_I4Z6(W;44kR{=sS{k`r3zMxTOs*&A88)k`z)N(jMUaBI{d{z z=$+9~my;NgMLE|9I&tDRRcPkhh*euZ4@7Cb0#QWXrujZ$R;QfwahdC30tQ~)RO={N$P}^I#@=rV03W# z1|zX*bRDwA%%oWL&p<-W0mE+M)KBp%nR#dkOVQc{i>hEi_Vr?dVvSX>C1qgR1Sg6K zPE;lc3zXzNUx=ce$_-M^Y(7j>8?uY?IJK3vg z&jG)ft{iqsjAJ`%=5XkHH5c|Ph6LNC`_QfjSqGeG!y~OKQ$Y`5Vw%MFinHLy;DtlX z;fmK&Svctky0U&(^`oN2ifO=N`_!%SyP&S|I+!zOm28CXOATT>)o!J}ivT3oP~YHi z5eeB^F}SaQs*fAJ7We0a+!)}ncN8Zs-v#$b;zWtUOFI)jmb~j7j>m zu0%)+g;Zi2MauXOO_b~wYG?cc?@LXR>!Z*EN5#i=d(`e8PPTifAqHKxm+`|eOT}Nv zUQ&jPUc$9Hph7T>p&6q=$w|VYY-m&0A?IiCT_0i`!`&=lE-coUFjP~gjKWF~XWL2relxD>5}5vgj?UK?iTabqMw- z3D3GkNa~$x9VkbCl40za5}t%&M-`16XFUhrC&{iMjzfocEpojI-?DB))6r{S(Swhd zLA7iV{rFMvOgq>tZ6lB6C~>n%(pq|pH<;Bd%RN8C?&f@mzo2KJzkqw-tVg*E6_N7X z_YZI%a4o*S;54lSQ=>fo;^a!NS>*u+v(?q$GUn|gC(GFmr6JV{e`>@KM*9yT*ZyN2 zn*3q@gXIJJkLCINN54x9|FOKk|1e0k{}7VL&>rPtu-4X>ffk;spjb!?v!rT+n87P` zXZVlhzW*?46#wzi24>Ob>VO$|@MY$1)LULgTgO{vZ87S^Jqv8%nSi{zV z7~YQzl_}4z8tpH>o>j$ zDu|Tk&$vT*4J^fQlFZ ztk+X=IFj*XF;5s4^Y92^~<91bQWGHuJ=}a6R#?R(ePENdMicvN&gvCyavR7U2btecDwMs-RfOH z^=4tU+U-)Uw^;NkLOSJ*Zq8$&sVh4BgRU~Dcg<5zFQq@wz=nK#6XW5p8Z#wSD=`nAz zZWr5j-NwDxUcTShA)CP4%)i4OyuTogmD+*Vm?7JNH*o$pju?4$h{+*$$-P|ajmdgb zR2cW?tBFhTYHxNYrlZKMdV7eml{XeW_P}!(F*r-LyhWuA2#ci)sQDaL}oZde;Vof~}#UTu49 z*fBSH()G@8pF1{0>z&!dj>l4+y2&+YXgu{A_O#&uqZJxjBQLuP$#!LWhp=uWm%!Op zHK{OK7<~(GAAUqP@QviUIfIAyxv96@b2RJQI6FOllHazP#_ebe z(yrOIz{_saZ5j3+$*R$8Cwjbpd#Y3WbbIPxO46QNa9|^~ip6ymSyjGIhV&+Eyhk;w zI=n@7fJWKTGkschg|x~J9`DyIa&&gH(wDFFTSaX-WV`W&L~tjbs)3?zhbpM3HaGgR z%wUI|6h-w)!`e|QyPb!fjHUMIhJ6t)U6Y1=0SA1aOI>Ae4WF`Qo3K%yn!3Qy6y8s- zHC4*sO}!l3jvi@x0b=xRu>!Uje3^A%CxCj|IQW*lj*oBR1mYXvF+92<9Z53w=vaKx z8rNOHj$>DJ^JPDp+(|DfbkevSjtp-o-hfPH`Hk%%x~l+wTlkA7a^)OrZ-v-Rzx41F zK63BZ5ZuFOqH|T~_dxK~dS_qS?RV2|DTT(>)-d}Hz!!V@uVIFQYwe59$k8qX@VE&X-oYrC@V zyWj}M-ik3EuTngR>$l?iKRst$ua@3WySx`$rAfhs3PN4=L7z&sDv3F z5T6dm^}0L_gqJ13%i!UiBYb9TXS;eP8^?IY+QDT{O41AmoAhJYcw=WditpM*`VQ37 zN@7<_7{_?eQ#ESEC3pxM^-+SFq3o^-?6^QzgyPhe4kR?n;q2u3=Ijme|A2tPxHFm{ zs?qmA)fhoZfcxkhNJai#`rJabQ{B`%a?baXhhgws^>p4860yGd!?xVBR#+sh&Tg{P z560y7+`-F;z`2$>%Q(hPjV!*{ICe6jcD{N^} z@iYEeMPGf6^z~a6{j77Oe-Q1h+~Ld7)D!jEM^DdnB4op!Qa%o_U6jv90@|?{5`;@J z%peZQzm)mSZZQM;ANrlF{;`>>Z@tgL_w=(Dlb#O^_2J|F7eLRK?d0qQS!?>W2K;X^ z^1y&_qo3Z4MSE8s&Wz?oc#X2Mmrl^b9_1CzEP`MTKjyD$lVCCM-q@B=c1wC_0hI1Yjw(q%n?`j8x8kzR%dYuFBfM_y&(-YO$A161td z(35*fE-+4DDz{y(fQAB4`2+!p^v!-_)WiQcp|0$o`77wQ}{*Z zQnd;x3b0OIDdsSDqToMxVd{d}OE%7E1KxS3H!MIvoa(YU6gBU*7{8ex9wpm)IgTY~ zC)IK}d6g&1sRt=M-r#A`L>~2&qfV-aVVQ~>*b-UO!9EzuUpA!h@SOCccgvh!3H|65 zG}RzA9VK&5;8twl({gLYbfy#U-_ACa6WR}JDC)xSmTPD&H|zeHhL*|QHc4nBW8&sryo3ojX4wgf9oXqMB zhwS?7yRw>X7tBxZ6+)k)@o^ze^(;{*+bwxA)w3ApsQ8EGncYgwX#zB)2x7(H}3wp8%K3Jee|>5$kH z=A@pMpj}`Gv@yG+-|3>qjz#yuKX1aT#uy_z(1{SU!((H9F{Wyos5|o~`Ww`!raP#S zMA&O=)YP3BqKT%PHT5St53eU<4_yT!|1lGZ_52g&%V;0{z>oCI399Hs6*}VT_hg0t zK#CnH%Z6m<{(wbF7X35Dh_Vum*gTg~sc)}6^A!wSRFZsF>EFP2cO<4CIRBMN{;$UU za{sqQc?<7>sz4f`&qGHpVPO#80(wH`feV+YEZ#4Yry(!)(2M?*rMy($Y0?v(YHQ3%bz{G zdeEZbRRH=iHx8GE&|ZFy@GCYvyk^jp;iH=iYKE5$+I-&d(f06gYGryx)`0LuH~J=^_0c;PrcXV;I+BR*%>uk3Mfpjygv zUmusl!2#;a{CrYQhMdLGr5X>L#5gXO^TC1sxTG+^XIVdbJQ#@2kih7E__Z1@>xWO& zcz-@8Yh2yG??nZ&ce*d;;Pe7RztRVRHQ=v5@4T`x56(U}5PdQaz5;l0;CQdEVgL7` zJorE5!TG1fz5u^1_#23x>7Ie`UBFq-W1q$WKH>xLdk}vE(X($4 zguf1)^;CZb2l$8&z%Mu64n$v=2eD#6a@A zC=dR*JoxAH;1l!Uu{`+HJors{@VY!WpJ*DWU4i@O%)Dn#)7ZwqSa-@eepT`-%CBqr zbtS*9;@5b7UCpm+_*KQPN-3@!7nr+rVdMNo3#Tl)fAOM)a~3A2E@}!i&R(!!QDb1~ z(rF78-939jz|p@`^{-!$SUA6NKFT%jpK5adbZ*m}IcMD_Fn8Ia`S&K#iu)TEe>Kp! zXkp{*ffX$sBxM#^cQd4Mwx$|e<%`Z7x96-rT^?kP-Hw6|h zT|60Ick`=ha$rt!_WXtX{)&7rmG5N>15NW50l_yAd;?iBf8qQkGaDBznT<9rnXk`* zqGj_J-ZP)5`UcsRsyMKCb`#}T=^tF_A6zBm>eAW5g)qUdW&Bzy80xv_-o;m;z4t&6 z_bwhExOef@Gw)q|HWaDKYfFq8WA`7{Dpzj-}v>s zYv3mRzp4q9@MGd@*cg0RKd0AzJzNRrr$7F_nt%y@0m^;)?b_*)-o!u7O7S6X>b=~+ zO}$@h;HKUu8aU@}{(bE{_|19n`Fj4)pPyw0Zt~M?;3hxSIsw9Z`t+kb`0PCRl05jj zJouw|@PE&P|I0`)h!6QJ!=Ep=20UuY4{_6O3#cS~h?{nsF>upvzpN(MXVGslaMRvC zO(EjL`c1q2k%61`^BHz>d`NHh$3_D;>HmwJA0N`2{^wCO;XmuX8!r}e!7ss~FQ1K{ z%HbxTSE&TSS@hQ%xM`p9JowFd@Z0m?v-05g<-wcs;AN3qyG*^@sOQ6!TN(a*Icza- zR_WvIdGP%PZuX1rJoujs+?0Qjo>!9}vh3e?R37|O25!o~&cJ!-*E8S1Id%2%#Rgt( z;D2Y}CjHk9yuzSgZ{Q~Vw+#Gq2K^=jH|hVkfnR3OKV{%1{bmEd+@SxJft&Q(44kEsq%BXk$6VW*Np}zdjWkx+w zfIdHS4cz3X*}!SqKK;W6ew~5y9e@0gPt%`FHt-23^Xut0a5mk?-!|}x2L5e!T6|bP zO~a>u)WEr@S?oVW7nZ#D4A2EN_{X#nlb^VOk23J720p>Sry00w z;EsXcVc-b^|2qRW`JAMUxW9a67`RElOgjbAoBf6FH0P&(J^yUrW^5*yo*4r-{oyeKztO1w72P>`-BI==Hp*v=fsEfrXKG$@EVl)^i2kSvw^Q>r^1Kzm~qkf4g40A`SokQnYvEoBMO}|}g;Poi;`M=1(zi8kQ1HaS2FEemc zkJlTx>2F;FZ!qeqGw?4N_KVQz94BQ;Qo-%NA-0U=PbA0TkGsTDXhw_V2Y)`k-@r}!ck|%G?`AD$*B>`neB<66KjwJ!4+dUh&~G$wbKHN=z%MrF zN6Z_z{!bXVSx>~kO+SB`ft%w zUN&%ZynDmI&2jns&*tRDL%%re zez?CcATV~xSMN{Gz8k;ECiOedKWdt@VD{MLoaM>D*n4ItX9vdKy<|yXY||p1jBQ+! zti(E4?hNZ;jf?KTA8TKMu?rU^=Zu|p^NcH&Bxg5%8C0xk&b*m(n`Ymy9i(FOFa9pW zm2A?Gel=9<^WjVS7SMN_p9^sk!e6xs;`r&WYhbkc{TP0DpTfSd#45xKH17Z0-0!|V zPFnNBKFK=&((CC9S?2}#Ge6Vy{b|$Y$8W#?I|+pYUH_QAUWf15D*X2Qzl_~^{kSZJ zIyk7W*J`>sj1i_kaTBEBPG=e4}6G{hA|dLIYm^ OsJcF>ezM>FumAt30R@Nv diff --git a/cmilos-fits/mil_sinrf.o b/cmilos-fits/mil_sinrf.o deleted file mode 100644 index 28697c53615b100ffad0d437cf9082b4df917cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15984 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 GZT~-o%$Lgm diff --git a/cmilos-fits/milos.o b/cmilos-fits/milos.o deleted file mode 100644 index 3ea856ce6e1041c1dddced0942c04a6689e868b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66864 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 diff --git a/cmilos/calculosCompartidos.o b/cmilos/calculosCompartidos.o deleted file mode 100644 index 7a2c59611575655749f93e96db2437d6898e3ef3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14648 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 TPidA-f5h}ZmeDi@cK!bV(4cNH diff --git a/cmilos/fgauss.o b/cmilos/fgauss.o deleted file mode 100644 index a468fbe1dbae07db2291b511df58c05bd78d91d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3824 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 diff --git a/cmilos/lib.o b/cmilos/lib.o deleted file mode 100644 index 1592b40703a2afb0158c87683ff72dd07a11512f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13464 zcmeHOeRNdEb$?G~*{8QBtgEZE~u0X|hk+g}1Ovhy}KYF(B5vg;XFc z?Z)^c63$A5SMjiF`?%?e+mO?w_3816-JGPsNgC?|^uec)0e{F%>=?UXAU4951=v=9 zcixQl?O3v%llJtVOpbPDeskyEJ9qBfx$|(EBeBH=s;Y>hDqm7^J%K7pNg&q_v1Ul| zD4$mJ+w^CstKS+okLatS=3#wh)O>GMG;!K6->f#W=QbK<+F$-FH;9b3$NY~|ZN~gY z*bMvKF|<~kCI;a)bPa3KdFmLZO_3+U`YIYpg8>$!+)h zePOdJ+WE?&Va=;WJI{PM66}j;i~IEKXrcD)zrq4yZBQWAw#HwQy{tY%W*XKt?-cy3 zDIC^TcMfaCN;*i`Vt4j(;WGs`#hNNN9}T%P*RWylGlgQzE5^Kfa6oJMH{cPoM>hxc z&z%fo#UcIJ?;_^g5p^V;GTK)9-Ogpt;6%lB?_*C9{>223}|cyUm(wm`5=>$gHbOW!rN&fK9os z1q*}0z-a&kuIC_F#fpcun!e^U!`j*dhWeY~O0Bra6U}zIquEPF=I1%~aqD~A-XFtG zhW#M}u2K`T?s7*0=ZW83ws~OMf!~VUOE~NzL?n;x4vdX)cx_`mCQdG zS$G_b*JBuk(g3y&?3fwp8!Py13u5oT1 z?k=t6Q5x$dH$+th?hqJe;gtHzPXD!LA_L9JoNd#8WXcfGDTp~v%5b1M>;#{Ffsg35XvD!y6 zODB^_qgAC&nKm+k%yQxmDHTrHHh0Ybw2jVORt}EKDkhNE3A0quXjO$%o{fN>bC|>H znm*8TZjc%x{`%f&_!Yd3wif?W=woLG;oAEQYpd5VyY><#e6K15kZs<_bk5ubm)5Qe zDTZZujo<vzo1AItG{0;CAvg3~n!BbqyIMH}g9zrp(#7ht-amMlVh^$zROmgHZ_HGABgd zLc*tj|6(TmJ6!mloNx~Ymowo$F1$1+JU8=kF8rySaC;_J?X#sZs)T6yf=7t_Y9D;6k{a9lAZNU@ z0&K@S&w~r=ut=KiF!bzc)i5t>Ew6%|VeKSeFs!|_D=}*)+205rf!i6u%jAR8E@6;d z!U%p4(jM(a1lP5PJHykCf|~aEdLkfi`w&5><&xHV1BGLFs$q5t|D~{x3ka6bN5v|r z@xXSz3f6J+Rj^JwU&Sc2%KYq1`PkSP!rH+zKfS~nhtGTljlf`FEYjMqwOl(oHWoGy zocYnaV`J?`cHhRmlu6uvhrUL?Ltm?}>*i4z8bAoyhnW%?#`sa4u#E`7J--;^d2=ZN z8J|2!2h&-U#&!@z{(K}Ux%m@!FrP(tnh%Qn`6bTz6L&D*XD_$73KaSCea`t4cQBtH zz2YiR^%IQCG2lLr+BK<*;Kfl~Lf8q}2vtvl}L6JYd!a4sVI%mFk87`A56X{Yr z0{74=Bk{XPV5r*Ye627r1kZZ4b);zn>fm_VsoQ5R)tMV&^rLk;#I zmqBJ$bFBH)a23W%4D~G1tktuwj%K^D&#U{R*(|^b{OXVG}OGp(tHL+&3%U1eRj5X-FACdy)M7OBoaUaWQl3>*}u~!Tp)< zlaec9CKAnkC33tV)_Ifv_H3u{hd2-Ha^?&ATE{W5 z@jwSa5_0xujsu)(XRmYfU7Uqg<~!^-RFmsJ%T8G9`KGT}tHxr9XJh7n+t17ngqIV{ z(-S8QEDHYYTWT#-=>2(Jm@X%;>nQF^6%IJXP)`OAHlHJXW9oBps64>VutS6Ycln4P zQS$?RRV?v_zEU?2!3@>-Jb+M=y@br;emubvA27p2waEM2EZXju;0n4q6gS_(ao3NX zjal2gumk&A5jI~?`@>q~LL`9La582s7zhmVxYs(Q?cPmuv+t=|%a72CVkS;Fr77{? zC?zqv`;yl33k+qi%+z-L7>(Bc^p}t=1p1kO6jjh$o-AEKFZoynqR^Z${j%H`C|>dv z$Xa^wl7FG$Q1D>-+A3?&jqJk)IambWMaIymab3c1F}iqrN7c7<^~K-`?ZF!4D->58 zVRJlwk<@_z(i!o7CoZE9r3SBH%UuJ_=giv^Emx-WLOU+i``8{JoQUzjK9%hda{-*2<)i`Z*VzDT={OQ6U|;OhAe+iNDH~LvA_t$_>rcs#u7ctp)`#})zM|v{N82O%Gqdl(fg>izv)k) z7h=4542PcfuSV6Oaa?^t5B8DD1(`SKV*~rXfX@nt5$MC}NI3Xf=6ljEkp8!}j!-ya znrpk;AXPU{=;j3@@kT^@^0012#waf!gT~CRn6=Qpm&_}Hk$9pXpR)=hIMznonm;FM zz8EzJ?0tZp`=hmZDZ3mI9L=&9`wgaz_ru7CsW3G=T zkh%=Ttyyok-K1+zzGEatqSpL(?ftrAxv>NKZ zN>g(@@fLhyCwnor{)F%VTRAgwK)^*o#aY3&QmUAQLVbj=(OzM0wcNfVZzI3jp^ z-uiySII~ts(g%z=dVU@JD9_QMA@X6M8 z;Ot%=A7@j1%#VjX%@>EY&mTeB*V&yrZ+PiYj4-cQi+)PMngs+A1zOM3E354>W`T%W_XUWE$)Z;!w58Hsn|2|N+)`x$SHEHKuFJ7}M##>3n{2 zi*IwLF1@)n-LPp}G#n$!ME#~MiA{H6XiIIvcaLw&hSc>azOu6ET%}3ouS+-7ZfS%H z$%)w{BsR*&@(F(|qa{^UH~UJfS5-%Ru}xbt+dk)8SXNQ?MO)EXTwnFxTNHJhSDjZh z)!k127zKPjA6xk;G%7vb2MY{O$?n34$7i`Bp3+@cg+1jvrY!MPWT%Ebd(^_~r%m@% zEcTS^p3+K>uhLV3Ih7u_PSgGPtKMRmmE-BGZ_Q<5z#`1*8@SNFIhL`R=K9-(oR zX8Hk-T?M+QWJjUy@nv1hJmm#fV7q{Lqx@gVAe)ozsXR+RSjX;yh^NG&b?kD%t~+QQ*(n8k zrh7_Z58K8|$i~Z@NSIl@6f9om{4$*1u7W7p(jZ$FtQAJYnlN634~tYjj@AH81*g3? z-`;Kikjco)rauHxYOG z4E8eTLr-Yip5bwOhI96O$YD;ntfG)!^VvU2DN2y$qJ;2Q&as08+(P@4TNzW9Bo=S}8|#IKI?8~A8`|M*Gx(f<6B^ZPU6heAF) zz_Eu2fX+O2R55?wne%rVo~Y24xReWH6O9#4_+KO_N+JF?Q7Hr`x!?;uxa4pjzc4h8 zi@uMaTbf^}uu19C(6KsL(&jeYg}Vq*Z>Ii|!1^df6QS>{|Sh z?d9@W02AS#2Tpv}Q*cN5mR%_~q9*(;jPhgmz)9}bA~aA~ zEJt03Kf?F0f6~n1_i=o{g9ZwV%cwQ%579qG8;8PTCTjY|LU=h}guwrS<416u1;<(30(Oq$zS(G? zuvmn86o15j#T-I&xQnlMJ2?gliwUT&=J^> zZqtUcgrct~TX@q=H!77YslG``)PJM4VY8B`t*fg~D5-{IQb{E?Zfd-%fik^YS*E9? z>bEAhDC^d3YOGHLgX>a_iP|kG(A6Q$QnqH&jY?hum)}d}cW(jM$ zD{31On`-OwI{8C!mLBF2*bpakNO3f8bhK}Bv~y|VgkV_NoUGlVG$d2?4V!BlxEYuw zMP#9{LT&m_K&V9QN}(>f_2gfHOu?Gm2mctXPO=lDGm{!5OxNw|yK`C$n!;`q}NzKHWV zD&Z|0e@?=8as0f5AL96!gwNt~r}8UK*mFL|Z;XXs-yz{IalBr_ z{ao(d625@r-<9w+oX^iVPF=o4v=n8ZME?U$e@w#9as1a3zL3jZ$FJ^j`*8Yt2^W5Q zpM*cb>Ax-E!au(&;eJm4goM{|{AmgQ3CDXR{5_5jN%#VepObLm=a(e>mz;hIuZ10i zKhKl!g}g812>Sau9+c?!@%~~77w6)3317tf!XAQu3&-z~=nwJ!4ha|j|6K_W^ZpYO zzKi#tmhj`e-y`AT91Tf$jQ7t;_#?c3Ny1;^{VCiZ#d^hgnJ3{ZIlVYHg8ng%2POJb z9A7NqV*a}vC$hY3mFIE9zZiewo|^5zo%h`$jtf3Ck4o4#==dCiI-5i(s z^gD1TpD52~iQb97JPCe?=d&_>BhN!+{GWLqD&sfvd{gMZ6Y{Bind3z7w8I>pZwh*m zr_STJOn;99cdqMo2ky*^d?Xx&_|TsyTX{p^;vMuI2^a66LlQ3DDdotUsR%yeo$`o; zi+9Q?2^a4aFIP_R5$}{m5-#2;^q;Ib<(BjPdrZRjaQu{ni+768kw+1Uc&99saPdyr zCgI|pa!A6(JH?q_5r6Sc+3LtQ2p8{^4ha|Ul;aYZwEIfwDk;w?ZjP)NkIL+=3Zf>eI=xCCgXcfKShf zzX2UFOKx13YN*|uB+LI{#fRzS3i6kN5HKpkVtsb^LvQbSz{w;bJ}xTbvvzA6zo#iY zlN^dkRQNGe=-o#+-!>Xz<;H77E5GJ$I}R>Di+IZOLwtUS-wR@bPc(Q<|927Md834j z`LbPvd{KucnQw6UGXx>$FV-*MukiWhd|XstBg3Ld=4ZMRF6P%b+JuYJ$mff`sKq?d z-;4%foIjdj{4RVh)_jG$!T4ZP78r5ZG;selm#i$KGGbe9Tk zhCgp{EZh2PsY|zZf41vyf4X)1qg%J-(@lbqfC>r7AE6bhuFcr0h*bj=^80?zy>I3w zWGwd64xh}t_r2%cckVgoo_p@O_dQm|-Km3u!GQk>25t!C&U`cwc-5#4!<86!8x{a^6-tT7I=IwR9{)dgI#7jn;UloG*xK->%%JAI~8SQuvMV?UD zJ(0q0RwXpJG~u=PId{Bma=!YoDr`O(1Wy5L%>p3JCkNrAy3krP zPtFQ>7Pi*hBWEF=jkeazlC!})E3?)#;EadmzZ!!3ME53d^p1F)6$iW%U748I5f8Q` zFPm$XcR1^7BjLGL$qpx7(pK5h+!Az}+W=JDcr4n{bj%KJx1;UJ^Mxs=@qJVoI%cnL zh&b`phpmSLxXXHJVS4<9@yZt0TM((5Yg^@e`SrZl?xi9rh+EM(jR)q&t&%Cah3Z)iB;(G7oYH=g8-1PkLdN(rO^`4Au zB%|w}l(qzSI*og3(hK&Xflo%NQG>mHLBvfo?sI~jFzW)xYjX-7(e1X`i8>wck;p7i zPEOZW1Zny-d{h(NYE9khw7yc{6l{qc1pySkf;D>GE~+3B>~J=!TJ1=kQ;^cSc_dPX zLI?Cm!5iok-oCUQ9OM=#F4aZkumj}@Z<}90s0UDu_d>!ukqDl4)^E{@crvmM1y1m7 z_Tep&(YV2X<1b*{a>^}uT=BOeQs{b*N9uq>;S*i&x1yvIF>j}BO*`NgY!W&OncUlG z_;UQlypvsTyU<%0CoXzRd5!m8mKZpFM@{;!aE%9p+Z5S=)0lS(Tr9=~@!(-{$qM6E zeCu)B3SR+&K%%k3hRxWluqwE#AQ>6YUiN90p-YvY=GS|KE+T~93OoP6S)YVbG=ok% zG$e(%R~2pm3S}`c2SDQp1>Y8HL`Rs;Q(RxiRxofbRm$Kzn)3G3k*=kw;uBhyRK zv0jZU;MT$=T@DyVpMmTABONPyjy3hU=2HdM+DMVmz-dN4|Jh%hjbyn&}C`_RLP+!|`OcxD-H$HiDx+HLOx@f2i zSw8~;cJQb1TNCVYVG=x~^K7Zy1DD-fxdSZ-7hTZY8sx#{#dBj;se3^oe#%3mc(S0l zaIRIi1Bdl3bFKOp=2{J{_-zL;A{55=C_7w8hd%+FHT?%PQOEo6*0JF8Q81nSY)#{9 z$0u9i&{2HXkAGd-jHA%+(BNYbTzVO=Q92UhR-8N3 z73-(c8i3Td;Rf+=^pKSb(Q5Ol=_e3{s0rGEma>|mrlJ1T;J z0*jzZEs4oivHd?Vwl?o2xM#TQHzvV;r|y;R^rJ%EolXQ}&*<)it_e#-D1)$ND+C!x zejc|(FFH{WdwP&jP+homBum1vrwdFt9DOc%U(9>S+Zn6C2)DcIZTQT1a8L3Yh(T(1 z(&IZTchJzwL!}fP?gok7)rQz4R7#tTo@ja{9_)-qyOI~zG@^H_nCixK36D)K2GO<5 zt4TK&HlG?=ZGE@Bdfkdhl^cEC`gW^3VN>KWw8r{&TVa=#x)!aiPW4);u{f~dcFN+b z_atlJvZ|>|D(GXnzm-6zCDd+d?I@UFI8=(RwR5gjYL~)d+0jN28iiBMZtH}GNLlhT ztfYWma5@_0cZQ+#`HUK%A9$$Zq0OfTd55gELx$1~u0V{5tA-*JjQv6>pYJ7?5FT%^-~M!XgTnM2!Uqt5L*1d;Ua{C`zsE_&}&yj%41y_C?VL3axl8R8XDxm5NZ9ZMLI3 zns#vji3N{G5sf6Tnw%~fAzaop?t$Y7hYl3fM#l4w2gxKI%YK9kh(-^9W5&Iryjf0q zd6=Zkax)2 zAFJ3C_c~);-L}`R)#>n>S%x~D;0I3dE$UJAD``92(pEH{eySogO6jh(=@29c-JOU< zPbRO%v72j=3Y(!$tEO=Wbx7UWFCgro^7ex}QC^MeWYJ9$ZCT%uPBs}*S%n@LK!3v_ z#9Frc{p57~_U&X=xOODHEPP{W?Z`s*0Nu%;Lcf=BC@Y0dv;FLyreF2xXPYIqqZG;@ z1yJ764q2izDEXmTh0VQ#ypz`2FBbTH%?iiS>o!XO*Qd|nD(OZ`FM=rIx|dCZ;A+-U;b2S{1K| zDeuUDati2Q=w3=$Hnk@mjQSc$7omC>bjC6&ZKQIJyB_!j*tg*%3X>I-CPPhXfFUVF z4VPFS8t1G}N!SW811t_G-4%E}*4hUZo$hZc_-yWxz{v8)tz36XPM|T}B6>j?2Or8CA!1-LN|D# zvV~nP*xZJptke!NN~?dCT@I07MQDiA+!BtSY&xt*v@7AnjNYcE19q?l16={8!*HGT zp>|Ar(jgeL5{A=^;67O6y^2dmN9~AXee)mx*xSp=I{4u<-1T~c2R#uHkaa+eQ%=48 z({8j4@xa^a7g7$Zqpv@^5mXWd-1((gL+nejyJ9o9S{JV(J*s5nzq-X*T{{Sd(Sn3P z=FpkmUcdYynH;U&VXZD_`JQ;?p3HCllq=sNv%%H9*6Kf@9+vOOeCAZP+{R>J6$;|4 zVV9=Zley{yDQw($kG1+~!aI25AAHc;J6GW#|3^*!TIPcHO}r_K-v&`BdQM1YRqoj! z?&g5g+={`yKGX@Hh(WI|)&s+f^+flsJd!CsiEGAM7pK^KSgRYE$ACqj^ZEi_PM5Qt z))Yc*{VF+>De2MtyI!Vp59UWO6ZF;(yYJxBxbFr`;T64kpKah(u0H!dB1y=JaZqMA zs?d5_-Lmvv^y2q3hu-Y%{S^cf$UM&@=qQkB;}Lp&AoC25LOl9+9?^<2kK;&XWH2?) zC31c65jSc=Z+T=e~&Ju2v}8l9}?!m z$`anQ0y2Ut(>1BgVGiM?abI!+YqT@SlL)9X+B*{$e7N#zz` z3U$z0yAv}QP%(rUAHg8x$9oi2xD?khwq=csLK-@yX_001yri(XXOM(`;oD)UydXzB zm55Lyx>)u(l7}S_4Bs9;iJ2;MchrPB~#n!lY5FujRYmWyp)A>3|n1$Fa zsR(H|a&(xtGEIwk1Oqj54vF;mQY1UWZtxXRSBV8(fQQgS%F2o)Wq?9^RU3I`+rq2ezE zmNl}9sj!anL%uTV;a1f}S}BtEiSa~TRk-X5xk~9n$U8+ppkV)K0SmFLN@j>gUdyYI zf7BXzVIYmvq)SRgAxbq?xfmmY3~1&Jtr_rs1mZ6bod+Fd)g$vW=tVV!dV~EdedX8C zPqc=j{WJufTuzl8C3Dcp+DiK zp&mOu=KB<^cgVJWvPts4XtuR>a-q^SJS!vjMB`S+YsIA4fl0vk*SAXa!76qy`yv~N z;X0PSDTo=EL?a}@G6#a*7g)U_6r+$OvjPcJNQ4r5s5S~zEn!O*N7663k}~OxRdngN zy%(M^StDs?hH-^Z8_lB&k_kEKqArY-dl1P7TPs_nU*(g}Ny_I;JbEH|Q7j$0O2$gG zlx+$9(b=eZ2(_<191}g;UZ;%(2j=(@u*ahq7}Verv!=GkntMaGcM?v3_Fw-eYi$PU z4XGP}1y25{n+NQX8R^I5J9xU?r(HlY%XCFaaG+!HR?_#%_rC07VS(zWE_y-ZoeA zetk{xB)j2$cEiY7lD30%%YEblc~QzPGB}N$!U~Me0aQPRHxpzQs2S>UG?km%jGZe=tbK*)AbhJ^lSV& zoSt|MfA_$Aw9~2Fq2|koyeM4Cpp?NEXUZWNKwrdh9U?J!Amlyaid1(*Vsn(OW0iNB zeql#@lh-(u4gHe(6jVd7`ci=or%VFu_5ui z)C|zaWeJ=MO)I#x2WiYohwj7_b(1VVV9JU4Cpv5KLy^ZIGaPJ|OdKQ$h-m{|(H6bF z*3ObtWED$L+dPT-m|0y6+h%rT1@)o`&;WHAdje2ZVceQ}fPDd_`d%z~3>5-V{6eaV zKWpt%lEmSn7w4@^xk0=f?8PmFK9JtB><&Tyym$G$(4m^MoXbcl>F-h3Q; z4IK#2cBAKF(e5r}%@DkyF?~D#FWLF8LFX@6VRrsl@KjCXVTiwP&xdPZ*AF8=D-Io$ z-r?ZFd2A=djTl6_CJX$T><1c|=udWkmnF#&tGO#C!m8}+&vrnkXXl8Jw?TsDRZQh2 z*)SA|A(d|t{6!ys7E^njw?QK5TR!|F$?~j1&8P<%A|@LUKd>r^9x|69Rp8f$@&&xG zrLs5Eo6Gm$_FvL49EZf1nIp(N_<0bN&yaE^p6<@(gUEJ47Jmkb3w0l7eMtoVJe&VP zoh5Au0qJv#OWO2QHIwOhhqtJf;ia4dfS(^iU?<+1$?`6A+3Yp{llkef-d-U^z6SNW zLbr=5MK1gf?iP9;C-s6C7y0+vm-&pO+fo!0ny>i8_5OWuJwll~_Tu^%d40*V=56<9 zeh(?1J&6~+W?p0drZW>kYrHnLC)0#X4SaZ}0wT7(p3LQtB`C&1a<;c;LuMT^PB_Rc zMCQip+>n_~(dFcY{aM}zvF7%1DuHu4R-5o%oN=4e{0Fu73fr#yZC04-3?3v7OL&nZ zq+}$7QdZ}^;donJ?=9E+z+R_q(|Z|bvF)L;GljcbB{=&Zk0!ZuQo(Q;6~uo`BBIal}^ILFJ6;^0BX5SwLX2__{IDF9n!*9VH1Aw~#4SSB<_ zadRo-(iIM{^#=V(#1vosn)PtaP3+A394tR$H_S62;#gDVF|PFP3*MzA-&!o5DBALI%$N$3N#v2Q(=L z=QN%P?hm%bSHDS#l=mrlpQ=ZERs~{plg4AD>L3F?gmW$p<9r|M_jZzkdDLIxFA%eC z`Ay7w6HpkZUBAac9S(wrt@vIX{~9FN-G$re%~&Z}=FG;)5Tyfh-=2__rOp_zrNka^ zR9{`kRR>DW2@XbS_J=`bt5Yyiu!8f=B1MSH<}rrzgk*J#;|Y*1NADiH=E_m4U2MVFjQ!38_8pQpi+wdU_{0ArH5Zew7@`BhYMxR_ndM464b zIF|BvBoh+*VL-?5SF#5j6b(|-rw}sKrS2eP>q;@>SD}(x!e{Cl5UaPNnWpFL2}r>w zKjmP?A?t|b02PHk;mBn1t`>~K0E%HUT8YX;$uFmbdDvWsmdYe>B@VJ%5B_TWUaa{A z2j|Z0tbEKq=QG=e1IqTVDcT&Xv(BB>>U^voo2cdbI~*WvEyIS6zkyV%&z;qI`B)w4 zvs&~wWp&=Uv#OVa&hAv#P0&)U#KGTAs*BHwRb>B=g6S{Stvb6h=sL~niD;HpH|qu* z535;yJptCyeNQl?k0(IED0@hMPmnWLXFzTNYCj-9I2C_D4tf|nx40N8=tMXqafBw= zsV0ryR&E=p;@}5gM<0pw1NODTL%LpT!g~p)+ntJxQ-OVs_4^appN_rbWkTQXrW?i; zIu)&s2a+~kg#J{lcxlcQa`SW{Z>Ra=)@g47==I%lq zUnIxiY8?)6^FMIjiZzk??cfYKYdUgisO>!&X(0^&8GsYsZ$PH*v3`>Zmzv)|o%KhY zig(m14E>O`h(?@H0JxS|p&uuVljPy@DPj>h_etn*`Di|vhAVTY!M5DDx4`U-RCjD)IxHMBYxd&|XD_o5)?ut}R24M$^6D;Oey*7oqsYIssB%+;5 z*E#8F;Y2zScB38G-{eGhV;CE@Gm*X#NT>Ck7L9bIuq3-~Jc6(0UOdY2AdYkgyb~K6 zTF@9~-@%dEBm(}znC>$j7-VCLhC+0uNc_>tG16g$jj3qawbg;t0LraVC}4NOQti*x za5o)h_ynrPoyuvN)xr0I$ACQsOm>g7rE9U@2nda|K<)i!+7LI#KD;*}j1abpaks1< z9D_#^!Iu)j!-?RbMDRDw3$W1z4+NB3tFOh>Gdpy;=-2BXQ9U5LndeEd8EOF0=+=bS z!p@rUgS1L=367(l?~{aHI`sM%IG3J|Pwq6blN71q~4k!pK{=r9e4 z-p(+fx3E7t5qu*N%p`)phXE}QA|!(WJpcoOyu|rH8MsIe@e8L?kAMXcJ~xot4U2+NHae&5=zYr%rDeAr`bgHm5=GwDeFkrnXR&+&~+ON+-PzhqX6A{H5-7_-?=wES}fUJrsqb06Wd?;dr#W z>6fa9!m}ggAnx64Xq0{L2519oKYnYINcUnFcedBC0qOhDh@EVN6MYK}t1jGarE0I# zin$2~*?sU-%|7hPM+Q{IUgznqz&#-DdF0y0?hnIsP%sLR+VAnUZ#sy*u+}dd=J*tv zHu=l11fvzObZh|SmL_3TMBJadG<=?zO$rCuNg}y>@vq7qc*t@WA$OO6yGzKoql{Wv ziB81P$GGX+!)|mt4aDVxQr~Wi59@N%cK~cx#-qW`cnXu;|20l_LYHH8;U93Aoj=}< zro0MEK_(iaRuA9|iE+w{K?l3CCPUCeINpSdf;_<}_) zj*0O9Q%3VSZYUEKpeeeM9MDQpX+vm~HXHbb;vlsFzq45~O0e6J>>2n~p(GRpVn&dH zJJAkhN-z7SwC3|#Szp6}o^(=GuWD7jMvqx&8d4!zp$!So2r2hDup#+ANF1ZuU&@X} zA4IFqvJVfS*l*qp4$V`_hPKZj^Jo@%jDm*Bugp!;jI7EilM|9ypKNEDBACk7g;cqaeHa<4n`@ z7r0%jSe;C)@muaq#;D7>FT<;LB5B235 z0R?kEYQXBx^>cp#*WfM7bqTqKH5Z4SW|h;N#aLr8RRe&j{`&szO}cwZ%wwdx9Gwz7cN66 z5uO_61+taBK3jxvq}xh8Oh&yoxKj!Y9N+_4r?^q*3*0D#OCOS(<1y;tR3@jkGLG>H zEzF4ZzV`AAYzM>JUEP?GTu$3rpf?U3c;H|>crcC!(aY7dT51hIV(9G@GHYbJgkh{u zUf#l%uL7zz^Lj@_mi`F^+JVA;AST#nA_T{f`mxqtib03Wu^f_Nl6kW*1J(Gux44yJ$TAFOYD=f=SF4|b5xy9k z)h-~c_NvuSp}kF2I#?$<_&s%iJ(`DNU2oXlUg%&t1;o2i7nOTl*{_DD3aAMRK|NY9 zL~U%vxWHI61l#Dd_#KPxdEj91h#ftgyj1qBsVc#W>|Co4_3$pN4h-=`g_q5z2f1pL zbJu@b$qUIif1(E|u~!(UJrt?Vpkh9cNJHvjs%M-S_BM zU{G3Mt?82X>gLEsuZ7UEYRn+jm^%?z_G!&c0#H(@&u>m6z+8L&Ud}$WK}p%ga~s_C zM{Ck;QuTDOPd-$mrr;>sswsuy5jw!W?fu?stJsP)p;h1(3q_cz1rOtUxs^IZ#b>up zVQ#@0KO5yD9G%Xm)Ey_?FgSo|^bjVKXx-SbF$C*im{xDr%Pb8T9oX(faH~YHd@aH( zCx~p+<1(p)$0F;c`E7KYM|OE>0Ta~B~u_QvC@ zat~hJ!534UW(8H^tJqOsGGq9~=dQVFv$VmV7X!Q;xfHy@!YW&R_3r`kaFBK}^-3qbwLF++qe1 zT)v$`q6isjwUB_yr@Uy@_+!6};7YOTI_z=?PsB5Z<$ojs%O0SMVqR8ULYj}%M@!@$ zH0UBZVlNE|$GV&HM1ob<|52f;T0hsTZ&=Ca8flBTGewQlqiB+U6)X$(rY=QMHTnma ztaY8d)+ByJvR2d5wQquo^D__}%vJ7hBv9_L1`BT5%fh8TfqLRzSC%ogwQWjz%msW~ zL^UeWEb*NT(^+TZDLUA4zJMZ(wNn?BlmoYedqGhotErnK4jFF5E{RQ&KV$xS7K(6M zLJBC5r!Iau?CO@*q%jtt+HUZ~4lYedk3lUkD!+<^?1X4QpYtoh6%H#w<_TM==fQlCXEEUpz_#~x z*V_L{XD&WNs zIlC;LpMp}YhpkeI?;&x~alCH_LqGszmA&jgRo2C}vRFEMKOCf!FFGM6i^KXNL{nH9 z$%5tZvN_Df(+?ymCEYO7*{`KbonC5^HAKA?^q}eA& zVKyhnAj4td?exk=sXinNPY_!hsUO`#;<8Lqn#};DAgNBN*Bx1@ z+sb%*dSE;+Ttx;P%_I4Z6(W;44kR{=sS{k`r3zMxTOs*&A88)k`z)N(jMUaBI{d{z z=$+9~my;NgMLE|9I&tDRRcPkhh*euZ4@7Cb0#QWXrujZ$R;QfwahdC30tQ~)RO={N$P}^I#@=rV03W# z1|zX*bRDwA%%oWL&p<-W0mE+M)KBp%nR#dkOVQc{i>hEi_Vr?dVvSX>C1qgR1Sg6K zPE;lc3zXzNUx=ce$_-M^Y(7j>8?uY?IJK3vg z&jG)ft{iqsjAJ`%=5XkHH5c|Ph6LNC`_QfjSqGeG!y~OKQ$Y`5Vw%MFinHLy;DtlX z;fmK&Svctky0U&(^`oN2ifO=N`_!%SyP&S|I+!zOm28CXOATT>)o!J}ivT3oP~YHi z5eeB^F}SaQs*fAJ7We0a+!)}ncN8Zs-v#$b;zWtUOFI)jmb~j7j>m zu0%)+g;Zi2MauXOO_b~wYG?cc?@LXR>!Z*EN5#i=d(`e8PPTifAqHKxm+`|eOT}Nv zUQ&jPUc$9Hph7T>p&6q=$w|VYY-m&0A?IiCT_0i`!`&=lE-coUFjP~gjKWF~XWL2relxD>5}5vgj?UK?iTabqMw- z3D3GkNa~$x9VkbCl40za5}t%&M-`16XFUhrC&{iMjzfocEpojI-?DB))6r{S(Swhd zLA7iV{rFMvOgq>tZ6lB6C~>n%(pq|pH<;Bd%RN8C?&f@mzo2KJzkqw-tVg*E6_N7X z_YZI%a4o*S;54lSQ=>fo;^a!NS>*u+v(?q$GUn|gC(GFmr6JV{e`>@KM*9yT*ZyN2 zn*3q@gXIJJkLCINN54x9|FOKk|1e0k{}7VL&>rPtu-4X>ffk;spjb!?v!rT+n87P` zXZVlhzW*?46#wzi24>Ob>VO$|@MY$1)LULgTgO{vZ87S^Jqv8%nSi{zV z7~YQzl_}4z8tpH>o>j$ zDu|Tk&$vT*4J^fQlFZ ztk+X=IFj*XF;5s4^Y92^~<91bQWGHuJ=}a6R#?R(ePENdMicvN&gvCyavR7U2btecDwMs-RfOH z^=4tU+U-)Uw^;NkLOSJ*Zq8$&sVh4BgRU~Dcg<5zFQq@wz=nK#6XW5p8Z#wSD=`nAz zZWr5j-NwDxUcTShA)CP4%)i4OyuTogmD+*Vm?7JNH*o$pju?4$h{+*$$-P|ajmdgb zR2cW?tBFhTYHxNYrlZKMdV7eml{XeW_P}!(F*r-LyhWuA2#ci)sQDaL}oZde;Vof~}#UTu49 z*fBSH()G@8pF1{0>z&!dj>l4+y2&+YXgu{A_O#&uqZJxjBQLuP$#!LWhp=uWm%!Op zHK{OK7<~(GAAUqP@QviUIfIAyxv96@b2RJQI6FOllHazP#_ebe z(yrOIz{_saZ5j3+$*R$8Cwjbpd#Y3WbbIPxO46QNa9|^~ip6ymSyjGIhV&+Eyhk;w zI=n@7fJWKTGkschg|x~J9`DyIa&&gH(wDFFTSaX-WV`W&L~tjbs)3?zhbpM3HaGgR z%wUI|6h-w)!`e|QyPb!fjHUMIhJ6t)U6Y1=0SA1aOI>Ae4WF`Qo3K%yn!3Qy6y8s- zHC4*sO}!l3jvi@x0b=xRu>!Uje3^A%CxCj|IQW*lj*oBR1mYXvF+92<9Z53w=vaKx z8rNOHj$>DJ^JPDp+(|DfbkevSjtp-o-hfPH`Hk%%x~l+wTlkA7a^)OrZ-v-Rzx41F zK63BZ5ZuFOqH|T~_dxK~dS_qS?RV2|DTT(>)-d}Hz!!V@uVIFQYwe59$k8qX@VE&X-oYrC@V zyWj}M-ik3EuTngR>$l?iKRst$ua@3WySx`$rAfhs3PN4=L7z&sDv3F z5T6dm^}0L_gqJ13%i!UiBYb9TXS;eP8^?IY+QDT{O41AmoAhJYcw=WditpM*`VQ37 zN@7<_7{_?eQ#ESEC3pxM^-+SFq3o^-?6^QzgyPhe4kR?n;q2u3=Ijme|A2tPxHFm{ zs?qmA)fhoZfcxkhNJai#`rJabQ{B`%a?baXhhgws^>p4860yGd!?xVBR#+sh&Tg{P z560y7+`-F;z`2$>%Q(hPjV!*{ICe6jcD{N^} z@iYEeMPGf6^z~a6{j77Oe-Q1h+~Ld7)D!jEM^DdnB4op!Qa%o_U6jv90@|?{5`;@J z%peZQzm)mSZZQM;ANrlF{;`>>Z@tgL_w=(Dlb#O^_2J|F7eLRK?d0qQS!?>W2K;X^ z^1y&_qo3Z4MSE8s&Wz?oc#X2Mmrl^b9_1CzEP`MTKjyD$lVCCM-q@B=c1wC_0hI1Yjw(q%n?`j8x8kzR%dYuFBfM_y&(-YO$A161td z(35*fE-+4DDz{y(fQAB4`2+!p^v!-_)WiQcp|0$o`77wQ}{*Z zQnd;x3b0OIDdsSDqToMxVd{d}OE%7E1KxS3H!MIvoa(YU6gBU*7{8ex9wpm)IgTY~ zC)IK}d6g&1sRt=M-r#A`L>~2&qfV-aVVQ~>*b-UO!9EzuUpA!h@SOCccgvh!3H|65 zG}RzA9VK&5;8twl({gLYbfy#U-_ACa6WR}JDC)xSmTPD&H|zeHhL*|QHc4nBW8&sryo3ojX4wgf9oXqMB zhwS?7yRw>X7tBxZ6+)k)@o^ze^(;{*+bwxA)w3ApsQ8EGncYgwX#zB)2x7(H}3wp8%K3Jee|>5$kH z=A@pMpj}`Gv@yG+-|3>qjz#yuKX1aT#uy_z(1{SU!((H9F{Wyos5|o~`Ww`!raP#S zMA&O=)YP3BqKT%PHT5St53eU<4_yT!|1lGZ_52g&%V;0{z>oCI399Hs6*}VT_hg0t zK#CnH%Z6m<{(wbF7X35Dh_Vum*gTg~sc)}6^A!wSRFZsF>EFP2cO<4CIRBMN{;$UU za{sqQc?<7>sz4f`&qGHpVPO#80(wH`feV+YEZ#4Yry(!)(2M?*rMy($Y0?v(YHQ3%bz{G zdeEZbRRH=iHx8GE&|ZFy@GCYvyk^jp;iH=iYKE5$+I-&d(f06gYGryx)`0LuH~J=^_0c;PrcXV;I+BR*%>uk3Mfpjygv zUmusl!2#;a{CrYQhMdLGr5X>L#5gXO^TC1sxTG+^XIVdbJQ#@2kih7E__Z1@>xWO& zcz-@8Yh2yG??nZ&ce*d;;Pe7RztRVRHQ=v5@4T`x56(U}5PdQaz5;l0;CQdEVgL7` zJorE5!TG1fz5u^1_#23x>7Ie`UBFq-W1q$WKH>xLdk}vE(X($4 zguf1)^;CZb2l$8&z%Mu64n$v=2eD#6a@A zC=dR*JoxAH;1l!Uu{`+HJors{@VY!WpJ*DWU4i@O%)Dn#)7ZwqSa-@eepT`-%CBqr zbtS*9;@5b7UCpm+_*KQPN-3@!7nr+rVdMNo3#Tl)fAOM)a~3A2E@}!i&R(!!QDb1~ z(rF78-939jz|p@`^{-!$SUA6NKFT%jpK5adbZ*m}IcMD_Fn8Ia`S&K#iu)TEe>Kp! zXkp{*ffX$sBxM#^cQd4Mwx$|e<%`Z7x96-rT^?kP-Hw6|h zT|60Ick`=ha$rt!_WXtX{)&7rmG5N>15NW50l_yAd;?iBf8qQkGaDBznT<9rnXk`* zqGj_J-ZP)5`UcsRsyMKCb`#}T=^tF_A6zBm>eAW5g)qUdW&Bzy80xv_-o;m;z4t&6 z_bwhExOef@Gw)q|HWaDKYfFq8WA`7{Dpzj-}v>s zYv3mRzp4q9@MGd@*cg0RKd0AzJzNRrr$7F_nt%y@0m^;)?b_*)-o!u7O7S6X>b=~+ zO}$@h;HKUu8aU@}{(bE{_|19n`Fj4)pPyw0Zt~M?;3hxSIsw9Z`t+kb`0PCRl05jj zJouw|@PE&P|I0`)h!6QJ!=Ep=20UuY4{_6O3#cS~h?{nsF>upvzpN(MXVGslaMRvC zO(EjL`c1q2k%61`^BHz>d`NHh$3_D;>HmwJA0N`2{^wCO;XmuX8!r}e!7ss~FQ1K{ z%HbxTSE&TSS@hQ%xM`p9JowFd@Z0m?v-05g<-wcs;AN3qyG*^@sOQ6!TN(a*Icza- zR_WvIdGP%PZuX1rJoujs+?0Qjo>!9}vh3e?R37|O25!o~&cJ!-*E8S1Id%2%#Rgt( z;D2Y}CjHk9yuzSgZ{Q~Vw+#Gq2K^=jH|hVkfnR3OKV{%1{bmEd+@SxJft&Q(44kEsq%BXk$6VW*Np}zdjWkx+w zfIdHS4cz3X*}!SqKK;W6ew~5y9e@0gPt%`FHt-23^Xut0a5mk?-!|}x2L5e!T6|bP zO~a>u)WEr@S?oVW7nZ#D4A2EN_{X#nlb^VOk23J720p>Sry00w z;EsXcVc-b^|2qRW`JAMUxW9a67`RElOgjbAoBf6FH0P&(J^yUrW^5*yo*4r-{oyeKztO1w72P>`-BI==Hp*v=fsEfrXKG$@EVl)^i2kSvw^Q>r^1Kzm~qkf4g40A`SokQnYvEoBMO}|}g;Poi;`M=1(zi8kQ1HaS2FEemc zkJlTx>2F;FZ!qeqGw?4N_KVQz94BQ;Qo-%NA-0U=PbA0TkGsTDXhw_V2Y)`k-@r}!ck|%G?`AD$*B>`neB<66KjwJ!4+dUh&~G$wbKHN=z%MrF zN6Z_z{!bXVSx>~kO+SB`ft%w zUN&%ZynDmI&2jns&*tRDL%%re zez?CcATV~xSMN{Gz8k;ECiOedKWdt@VD{MLoaM>D*n4ItX9vdKy<|yXY||p1jBQ+! zti(E4?hNZ;jf?KTA8TKMu?rU^=Zu|p^NcH&Bxg5%8C0xk&b*m(n`Ymy9i(FOFa9pW zm2A?Gel=9<^WjVS7SMN_p9^sk!e6xs;`r&WYhbkc{TP0DpTfSd#45xKH17Z0-0!|V zPFnNBKFK=&((CC9S?2}#Ge6Vy{b|$Y$8W#?I|+pYUH_QAUWf15D*X2Qzl_~^{kSZJ zIyk7W*J`>sj1i_kaTBEBPG=e4}6G{hA|dLIYm^ OsJcF>ezM>FumAt30R@Nv diff --git a/cmilos/mil_sinrf.o b/cmilos/mil_sinrf.o deleted file mode 100644 index 28697c53615b100ffad0d437cf9082b4df917cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15984 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 GZT~-o%$Lgm diff --git a/cmilos/milos.o b/cmilos/milos.o deleted file mode 100644 index 0a08cb9616b47273261f1060b5d6b62188366872..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61744 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