From 0253d18164cdf1e31299858fb2de49da2f192997 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Fri, 24 Jun 2022 13:29:21 +0200 Subject: [PATCH 01/41] mccd interpolation: Added output_file_pattern as option --- example/cfis/config_tile_Sx_exp_mccd.ini | 25 ++- scripts/jupyter/plot_spectro_areas.ipynb | 243 ++++++++++++++++------- shapepipe/modules/mccd_fit_val_runner.py | 13 +- 3 files changed, 205 insertions(+), 76 deletions(-) diff --git a/example/cfis/config_tile_Sx_exp_mccd.ini b/example/cfis/config_tile_Sx_exp_mccd.ini index 66e041e10..0efba24c5 100644 --- a/example/cfis/config_tile_Sx_exp_mccd.ini +++ b/example/cfis/config_tile_Sx_exp_mccd.ini @@ -21,7 +21,7 @@ RUN_NAME = run_sp_tile_Sx_exp_SxSePsf # Module name, single string or comma-separated list of valid module runner names MODULE = sextractor_runner, sextractor_runner, setools_runner, mccd_preprocessing_runner, mccd_fit_val_runner, - merge_starcat_runner, mccd_plots_runner + mccd_fit_val_runner, merge_starcat_runner, mccd_plots_runner # Run mode, SMP or MPI MODE = SMP @@ -47,7 +47,7 @@ OUTPUT_DIR = $SP_RUN/output [JOB] # Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial -SMP_BATCH_SIZE = 4 +SMP_BATCH_SIZE = 16 # Timeout value (optional), default is None, i.e. no timeout limit applied TIMEOUT = 96:00:00 @@ -223,7 +223,8 @@ FILE_PATTERN = star_split_ratio_80, star_split_ratio_20 FILE_EXT = .fits, .fits -[MCCD_FIT_VAL_RUNNER] +# Create validation catalogue (PSF interpolated to test star positions) +[MCCD_FIT_VAL_RUNNER_RUN_1] # Path to MCCD config file CONFIG_PATH = $SP_CONFIG/config_MCCD.ini @@ -235,9 +236,25 @@ VERBOSE = False NUMBERING_SCHEME = -0000000 +[MCCD_FIT_VAL_RUNNER_RUN_2] + +# Path to MCCD config file +CONFIG_PATH = $SP_CONFIG/config_MCCD.ini + +MODE = FIT_VALIDATION + +VERBOSE = False + +FILE_PATTERN = train_star_selection, train_star_selection + +NUMBERING_SCHEME = -0000000 + +OUTPUT_FILE_PATTERN = 'trainig_psf' + + [MERGE_STARCAT_RUNNER] -INPUT_DIR = last:mccd_fit_val_runner +INPUT_DIR = last:mccd_fit_val_runner_run_1 # Path to MCCD config file CONFIG_PATH = $SP_CONFIG/config_MCCD.ini diff --git a/scripts/jupyter/plot_spectro_areas.ipynb b/scripts/jupyter/plot_spectro_areas.ipynb index 7d4f5aed1..09699b9d9 100644 --- a/scripts/jupyter/plot_spectro_areas.ipynb +++ b/scripts/jupyter/plot_spectro_areas.ipynb @@ -9,9 +9,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Warning: surveys missing because pymangle is not installed\n" + ] + } + ], "source": [ "import os\n", "import sys\n", @@ -45,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -74,6 +82,10 @@ "# - AGES:\n", "# http://vizier.cfa.harvard.edu/viz-bin/VizieR-3?-source=J/ApJS/200/8/sources\n", "\n", + "# Other data\n", + "# - HSC Hectomap field, star catalogue\n", + "# From Wentao Luo\n", + "\n", "# Download directory\n", "cat_home = '{}/astro/data/CFIS/spectro_surveys'.format(os.environ['HOME'])" ] @@ -87,7 +99,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -180,19 +192,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HectoMap-HSC-stars: 85734 objects in total, 85734/85734 = 100.0% potentially in UNIONS footprint\n" + ] + } + ], "source": [ "surveys = []\n", "\n", "#use = ['Test', '3DHST-AEGIS', '3DHST-GOODS-N', 'DEEP2+3', 'AGES',\n", "# 'HectoMap-groups', 'DECaLS-groups']\n", "\n", - "use = ['DEEP2+3', 'AGES', 'HectoMap-groups',\n", - " 'CMASSLOWZ12-N', 'CMASSLOWZ12-S', 'eBOSSLRG14-N', 'eBOSSLRG14-S', 'NYUVAGC-N', \n", - " 'eBOSSLRGCMASS16-N', 'eBOSSLRGCMASS16-S', 'eBOSSELG16-N',\n", - " 'eBOSSQSO16-N', 'eBOSSQSO16-S']\n", + "#use = ['DEEP2+3', 'AGES', 'HectoMap-groups',\n", + "# 'CMASSLOWZ12-N', 'CMASSLOWZ12-S', 'eBOSSLRG14-N', 'eBOSSLRG14-S', 'NYUVAGC-N', \n", + "# 'eBOSSLRGCMASS16-N', 'eBOSSLRGCMASS16-S', 'eBOSSELG16-N',\n", + "# 'eBOSSQSO16-N', 'eBOSSQSO16-S']\n", + "\n", + "use = ['HectoMap-HSC-stars']\n", + "\n", + "do_SDSS = False\n", "\n", "if 'Test' in use:\n", " surveys.append(Survey.from_array('Test', 'orange',\n", @@ -269,6 +293,11 @@ " '{}/asu.fit'.format(cat_home),\n", " key_ra='RAJ2000', key_dec='DEJ2000'))\n", " \n", + "if 'HectoMap-HSC-stars'in use:\n", + " surveys.append(Survey.from_fits('HectoMap-HSC-stars', 'red',\n", + " '{}/HECTOMAP_stars.fits'.format(cat_home),\n", + " key_ra='ira', key_dec='idec'))\n", + " \n", "if 'DECaLS-groups'in use:\n", " surveys.append(Survey.from_fits('DECaLS-groups', 'cyan',\n", " '{}/DESI_NGC_group_cut.txt.fits'.format(cat_home),\n", @@ -284,65 +313,52 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ - "fraction = {}\n", - "fraction['N'] = {} # np.zeros(shape=(len(surveys), len(surveys)))\n", - "fraction['S'] = {} # np.zeros(shape=(len(surveys), len(surveys)))\n", + "if do_SDSS:\n", + " fraction = {}\n", + " fraction['N'] = {} # np.zeros(shape=(len(surveys), len(surveys)))\n", + " fraction['S'] = {} # np.zeros(shape=(len(surveys), len(surveys)))\n", "\n", - "tolerance = 1.0 * u.arcsec\n", + " tolerance = 1.0 * u.arcsec\n", "\n", - "for s1 in surveys:\n", - " if len(s1._ra) == 0:\n", - " continue\n", + " for s1 in surveys:\n", + " if len(s1._ra) == 0:\n", + " continue\n", " \n", - " c1 = SkyCoord(ra=s1._ra, dec=s1._dec, unit='deg')\n", + " c1 = SkyCoord(ra=s1._ra, dec=s1._dec, unit='deg')\n", "\n", - " for s2 in surveys:\n", - " if len(s2._ra) == 0:\n", - " continue\n", + " for s2 in surveys:\n", + " if len(s2._ra) == 0:\n", + " continue\n", " \n", - " c2 = SkyCoord(ra=s2._ra, dec=s2._dec, unit='deg')\n", + " c2 = SkyCoord(ra=s2._ra, dec=s2._dec, unit='deg')\n", "\n", - " idx, d2d, d3d = match_coordinates_sky(c1, c2, nthneighbor=1)\n", + " idx, d2d, d3d = match_coordinates_sky(c1, c2, nthneighbor=1)\n", "\n", - " idx_close = d2d > tolerance\n", - " id_sub = np.where(idx_close==True)[0]\n", + " idx_close = d2d > tolerance\n", + " id_sub = np.where(idx_close==True)[0]\n", " \n", - " for hemisph in ['N', 'S']:\n", - " if re.search('-{}'.format(hemisph), s1.name) and \\\n", - " re.search('-{}'.format(hemisph), s2.name):\n", + " for hemisph in ['N', 'S']:\n", + " if re.search('-{}'.format(hemisph), s1.name) and \\\n", + " re.search('-{}'.format(hemisph), s2.name):\n", "\n", - " if s1.name not in fraction[hemisph]:\n", - " fraction[hemisph][s1.name] = {}\n", + " if s1.name not in fraction[hemisph]:\n", + " fraction[hemisph][s1.name] = {}\n", " \n", - " fraction[hemisph][s1.name][s2.name] = len(id_sub) / len(idx)\n", + " fraction[hemisph][s1.name][s2.name] = len(id_sub) / len(idx)\n", " \n", - " print(s1.name, s2.name, end='\\t\\t')\n", - " print(' {}/{} = {:.2f}% objects not matched'\n", - " ''.format(len(id_sub), len(idx), 100*fraction[hemisph][s1.name][s2.name]))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_N = pd.DataFrame(fraction['N'])\n", - "df_N.style.background_gradient(cmap='coolwarm').set_precision(2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_S = pd.DataFrame(fraction['S'])\n", - "df_S.style.background_gradient(cmap='coolwarm').set_precision(2)" + " print(s1.name, s2.name, end='\\t\\t')\n", + " print(' {}/{} = {:.2f}% objects not matched'\n", + " ''.format(len(id_sub), len(idx), 100*fraction[hemisph][s1.name][s2.name]))\n", + "\n", + " df_N = pd.DataFrame(fraction['N'])\n", + " df_N.style.background_gradient(cmap='coolwarm').set_precision(2)\n", + " \n", + " df_S = pd.DataFrame(fraction['S'])\n", + " df_S.style.background_gradient(cmap='coolwarm').set_precision(2)" ] }, { @@ -362,9 +378,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27291 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_u.txt'\n", + "12621 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_r.txt'\n", + "5363 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_i.txt'\n", + "5065 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_z.txt'\n" + ] + } + ], "source": [ "# Variables\n", "unit = 'deg'\n", @@ -376,8 +403,8 @@ "d = 0.5\n", "\n", "# Input tiles ID files\n", - "sp_home = '{}/astro/repositories/github/shapepipe'.format(os.environ['HOME'])\n", - "tiles_dir = '{}/aux/CFIS/tiles_202011'.format(sp_home)\n", + "sp_home = '{}/shapepipe'.format(os.environ['HOME'])\n", + "tiles_dir = '{}/auxdir/CFIS/tiles_202011'.format(sp_home)\n", "tiles_ID = {}\n", "for band in bands:\n", " tiles_ID[band] = '{}/tiles_{}.txt'.format(tiles_dir, band)\n", @@ -402,9 +429,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HectoMap-HSC-stars\n", + " 235.97deg_41.81deg_248.90deg_44.90deg\n", + " 38 u-band images in overlap area found\n", + " 104 r-band images in overlap area found\n", + " 0 i-band images in overlap area found\n", + " 0 z-band images in overlap area found\n" + ] + } + ], "source": [ "import imp\n", "imp.reload(cfis)\n", @@ -446,9 +486,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HectoMap-HSC-stars: 27 common tiles in ur\n" + ] + } + ], "source": [ "ID = {}\n", "for s in surveys:\n", @@ -474,13 +522,24 @@ " print('{}: {} common tiles in {}'.format(s.name, len(ID[s.name]['all']), bands_str))\n", " \n", "# Write to text files\n", + "\n", "for s in surveys:\n", + " ## All bands are present\n", " if len(ID[s.name]['all']) > 0:\n", " #out_path = '{}_{}.txt'.format(tiles_all_ID_base, s.name)\n", " out_path = '{}{}_{}.txt'.format(tiles_ID_base, bands_str, s.name)\n", " f = open(out_path, 'w')\n", " f.write('\\n'.join(ID[s.name]['all']))\n", " f.write('\\n')\n", + " f.close()\n", + " \n", + " ## Only r-band is present\n", + " this_band = 'r'\n", + " if len(ID[s.name][this_band]) > 0:\n", + " out_path = '{}{}_{}.txt'.format(tiles_ID_base, this_band, s.name)\n", + " f = open(out_path, 'w')\n", + " f.write('\\n'.join(ID[s.name][this_band]))\n", + " f.write('\\n')\n", " f.close()" ] }, @@ -494,9 +553,39 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HectoMap-HSC-stars\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/mkilbing/.conda/envs/shapepipe/lib/python3.9/site-packages/skymapper/map.py:198: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " self.fig.show()\n", + "/home/mkilbing/.conda/envs/shapepipe/lib/python3.9/site-packages/skymapper/projection.py:464: RuntimeWarning: invalid value encountered in arcsin\n", + " lat = np.arcsin((self.C - (rho * self.n)**2)/(2*self.n)) / DEG2RAD\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "# Image size\n", "size = cfis.size[image_type] / 2\n", @@ -575,9 +664,23 @@ " ra = s._ra\n", " dec = s._dec\n", " map.scatter(ra, dec, marker='o', color=s.color, edgecolors='none', alpha=1)\n", - " \n", - " # Draw grid\n", - " map.grid(sep=sep)\n", + "\n", + " # Get limits\n", + " xlim = map.ax.get_xlim()\n", + " ylim = map.ax.get_ylim()\n", + " dx = xlim[1] - xlim[0]\n", + " dy = ylim[1] - ylim[0]\n", + "\n", + " while True:\n", + " # Draw grid\n", + " map.grid(sep=sep)\n", + " \n", + " # If plot size allows for one or fewer grid lines and ticks:\n", + " # decrease grid separation and redraw\n", + " if min(dx, dy) > sep:\n", + " break\n", + " else:\n", + " sep = round(sep / 2)\n", " \n", " #ra_min_max = ra_all.min(), ra_all.max()\n", " ra_min_max = s._min_ra, s._max_ra\n", @@ -588,7 +691,7 @@ " map.title(s.name)\n", "\n", " map.focus(np.array(ra_min_max), np.array(dec_min_max), pad=0.25)\n", - "\n", + " \n", " map.savefig('{}_spherical.pdf'.format(s.name))\n", " plt.show()" ] @@ -617,7 +720,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.9.13" } }, "nbformat": 4, diff --git a/shapepipe/modules/mccd_fit_val_runner.py b/shapepipe/modules/mccd_fit_val_runner.py index cb959e31c..084d54a31 100644 --- a/shapepipe/modules/mccd_fit_val_runner.py +++ b/shapepipe/modules/mccd_fit_val_runner.py @@ -42,7 +42,16 @@ def mccd_fit_val_runner( # Prepare inputs to run the main fit function output_dir = run_dirs['output'] + '/' fit_saving_name = 'fitted_model' - val_saving_name = 'validation_psf' + + # Output file name + if config.has_option(module_config_sec, 'OUTPUT_FILE_PATTERN'): + output_file_pattern = config.get( + module_config_sec, + 'OUTPUT_FILE_PATTERN' + ) + else: + output_file_pattern = 'validation_psf' + # Extract the training star catalog trainstar_path = input_file_list[0] # Validation stars are in the second position of the list @@ -71,7 +80,7 @@ def mccd_fit_val_runner( output_dir=output_dir, file_number_string=file_number_string, w_log=w_log, - val_saving_name=val_saving_name, + val_saving_name=output_file_pattern, ) else: From cce7030753536a1370e6718c81b9d4950e561d05 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Fri, 21 Oct 2022 09:10:47 +0200 Subject: [PATCH 02/41] reset nb --- scripts/jupyter/plot_spectro_areas.ipynb | 110 ++++------------------- 1 file changed, 16 insertions(+), 94 deletions(-) diff --git a/scripts/jupyter/plot_spectro_areas.ipynb b/scripts/jupyter/plot_spectro_areas.ipynb index 09699b9d9..b881d208c 100644 --- a/scripts/jupyter/plot_spectro_areas.ipynb +++ b/scripts/jupyter/plot_spectro_areas.ipynb @@ -9,17 +9,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Warning: surveys missing because pymangle is not installed\n" - ] - } - ], + "outputs": [], "source": [ "import os\n", "import sys\n", @@ -53,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -99,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -192,17 +184,9 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HectoMap-HSC-stars: 85734 objects in total, 85734/85734 = 100.0% potentially in UNIONS footprint\n" - ] - } - ], + "outputs": [], "source": [ "surveys = []\n", "\n", @@ -313,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -378,20 +362,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "27291 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_u.txt'\n", - "12621 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_r.txt'\n", - "5363 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_i.txt'\n", - "5065 image files found in input file '/home/mkilbing/shapepipe/auxdir/CFIS/tiles_202011/tiles_z.txt'\n" - ] - } - ], + "outputs": [], "source": [ "# Variables\n", "unit = 'deg'\n", @@ -429,22 +402,9 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HectoMap-HSC-stars\n", - " 235.97deg_41.81deg_248.90deg_44.90deg\n", - " 38 u-band images in overlap area found\n", - " 104 r-band images in overlap area found\n", - " 0 i-band images in overlap area found\n", - " 0 z-band images in overlap area found\n" - ] - } - ], + "outputs": [], "source": [ "import imp\n", "imp.reload(cfis)\n", @@ -486,17 +446,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HectoMap-HSC-stars: 27 common tiles in ur\n" - ] - } - ], + "outputs": [], "source": [ "ID = {}\n", "for s in surveys:\n", @@ -553,39 +505,9 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HectoMap-HSC-stars\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/mkilbing/.conda/envs/shapepipe/lib/python3.9/site-packages/skymapper/map.py:198: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", - " self.fig.show()\n", - "/home/mkilbing/.conda/envs/shapepipe/lib/python3.9/site-packages/skymapper/projection.py:464: RuntimeWarning: invalid value encountered in arcsin\n", - " lat = np.arcsin((self.C - (rho * self.n)**2)/(2*self.n)) / DEG2RAD\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "# Image size\n", "size = cfis.size[image_type] / 2\n", @@ -720,7 +642,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.9.7" } }, "nbformat": 4, From 055c27bf842c63a1e4a305f999700c7bf10041cf Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Fri, 21 Oct 2022 09:29:16 +0200 Subject: [PATCH 03/41] updated files from develop branch --- shapepipe/modules/mccd_fit_val_runner.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/shapepipe/modules/mccd_fit_val_runner.py b/shapepipe/modules/mccd_fit_val_runner.py index 084d54a31..cb959e31c 100644 --- a/shapepipe/modules/mccd_fit_val_runner.py +++ b/shapepipe/modules/mccd_fit_val_runner.py @@ -42,16 +42,7 @@ def mccd_fit_val_runner( # Prepare inputs to run the main fit function output_dir = run_dirs['output'] + '/' fit_saving_name = 'fitted_model' - - # Output file name - if config.has_option(module_config_sec, 'OUTPUT_FILE_PATTERN'): - output_file_pattern = config.get( - module_config_sec, - 'OUTPUT_FILE_PATTERN' - ) - else: - output_file_pattern = 'validation_psf' - + val_saving_name = 'validation_psf' # Extract the training star catalog trainstar_path = input_file_list[0] # Validation stars are in the second position of the list @@ -80,7 +71,7 @@ def mccd_fit_val_runner( output_dir=output_dir, file_number_string=file_number_string, w_log=w_log, - val_saving_name=output_file_pattern, + val_saving_name=val_saving_name, ) else: From adbda7d1d0b2078d7e9505b0da091fd0a2e2f8f2 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Fri, 21 Oct 2022 09:29:51 +0200 Subject: [PATCH 04/41] updated files from develop branch --- example/cfis/config_tile_Sx_exp_mccd.ini | 25 ++++-------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/example/cfis/config_tile_Sx_exp_mccd.ini b/example/cfis/config_tile_Sx_exp_mccd.ini index 0efba24c5..66e041e10 100644 --- a/example/cfis/config_tile_Sx_exp_mccd.ini +++ b/example/cfis/config_tile_Sx_exp_mccd.ini @@ -21,7 +21,7 @@ RUN_NAME = run_sp_tile_Sx_exp_SxSePsf # Module name, single string or comma-separated list of valid module runner names MODULE = sextractor_runner, sextractor_runner, setools_runner, mccd_preprocessing_runner, mccd_fit_val_runner, - mccd_fit_val_runner, merge_starcat_runner, mccd_plots_runner + merge_starcat_runner, mccd_plots_runner # Run mode, SMP or MPI MODE = SMP @@ -47,7 +47,7 @@ OUTPUT_DIR = $SP_RUN/output [JOB] # Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial -SMP_BATCH_SIZE = 16 +SMP_BATCH_SIZE = 4 # Timeout value (optional), default is None, i.e. no timeout limit applied TIMEOUT = 96:00:00 @@ -223,8 +223,7 @@ FILE_PATTERN = star_split_ratio_80, star_split_ratio_20 FILE_EXT = .fits, .fits -# Create validation catalogue (PSF interpolated to test star positions) -[MCCD_FIT_VAL_RUNNER_RUN_1] +[MCCD_FIT_VAL_RUNNER] # Path to MCCD config file CONFIG_PATH = $SP_CONFIG/config_MCCD.ini @@ -236,25 +235,9 @@ VERBOSE = False NUMBERING_SCHEME = -0000000 -[MCCD_FIT_VAL_RUNNER_RUN_2] - -# Path to MCCD config file -CONFIG_PATH = $SP_CONFIG/config_MCCD.ini - -MODE = FIT_VALIDATION - -VERBOSE = False - -FILE_PATTERN = train_star_selection, train_star_selection - -NUMBERING_SCHEME = -0000000 - -OUTPUT_FILE_PATTERN = 'trainig_psf' - - [MERGE_STARCAT_RUNNER] -INPUT_DIR = last:mccd_fit_val_runner_run_1 +INPUT_DIR = last:mccd_fit_val_runner # Path to MCCD config file CONFIG_PATH = $SP_CONFIG/config_MCCD.ini From 9cd31b57ac607c39d86688a9fc15b61203627636 Mon Sep 17 00:00:00 2001 From: Fabian Hervas Date: Mon, 14 Nov 2022 16:59:34 +0100 Subject: [PATCH 05/41] Added COLNUM variable to exposure finder runner --- shapepipe/modules/find_exposures_package/__init__.py | 4 +++- .../modules/find_exposures_package/find_exposures.py | 8 +++++--- shapepipe/modules/find_exposures_runner.py | 6 +++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/shapepipe/modules/find_exposures_package/__init__.py b/shapepipe/modules/find_exposures_package/__init__.py index bc5bbc591..0b0debcc7 100644 --- a/shapepipe/modules/find_exposures_package/__init__.py +++ b/shapepipe/modules/find_exposures_package/__init__.py @@ -25,7 +25,9 @@ Module-specific config file entries =================================== -None +COLNUM : int + Column number to find exposure in fits header of tile image for the HISTORY + string """ __all__ = ['find_exposures.py'] diff --git a/shapepipe/modules/find_exposures_package/find_exposures.py b/shapepipe/modules/find_exposures_package/find_exposures.py index ef0175c5d..494118e76 100644 --- a/shapepipe/modules/find_exposures_package/find_exposures.py +++ b/shapepipe/modules/find_exposures_package/find_exposures.py @@ -28,11 +28,12 @@ class FindExposures(): """ - def __init__(self, img_tile_path, output_path, w_log): + def __init__(self, img_tile_path, output_path, w_log, colnum): self._img_tile_path = img_tile_path self._output_path = output_path self._w_log = w_log + self._colnum = colnum def process(self): """Process. @@ -83,10 +84,11 @@ def get_exposure_list(self): temp = _hist.split(' ') pattern = r'(.*)\.{1}.*' - pattern_match = re.search(pattern, temp[3]) + pattern_match = re.search(pattern, temp[self._colnum]) if not pattern_match: raise IndexError( - f're match \'{pattern}\' failed for filename \'{temp[3]}\'' + f're match \'{pattern}\' failed for filename' + + f' \'{temp[self._colnum]}\'' ) exp_name = pattern_match.group(1) diff --git a/shapepipe/modules/find_exposures_runner.py b/shapepipe/modules/find_exposures_runner.py index 59531c43b..66a80f4f0 100644 --- a/shapepipe/modules/find_exposures_runner.py +++ b/shapepipe/modules/find_exposures_runner.py @@ -32,11 +32,15 @@ def find_exposures_runner( # Create output ascii file name output_path = f'{run_dirs["output"]}/exp_numbers{file_number_string}.txt' + # Give clumn number for exposure name in fits header + colnum = config.getint(module_config_sec, 'COLNUM') + # Create find exposures class instance find_exp_inst = find_exposures.FindExposures( input_file_name, output_path, - w_log + w_log, + colnum, ) # Run processing From 7f3b291dfa1d535fded751bb6abc0cf98f3788f6 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 16 Nov 2022 09:26:18 +0100 Subject: [PATCH 06/41] optimal number of objects for parallel ngmix (#591) * added script get_number_objects and modified job_sp script * Update scripts/python/get_number_objects.py Co-authored-by: Samuel Farrens * Update scripts/python/get_number_objects.py Co-authored-by: Samuel Farrens * remove unnecessary comment (PR review) Co-authored-by: Samuel Farrens --- scripts/python/get_number_objects.py | 306 +++++++++++++++++++++++++++ scripts/sh/job_sp.bash | 9 +- 2 files changed, 313 insertions(+), 2 deletions(-) create mode 100755 scripts/python/get_number_objects.py diff --git a/scripts/python/get_number_objects.py b/scripts/python/get_number_objects.py new file mode 100755 index 000000000..67cdb294d --- /dev/null +++ b/scripts/python/get_number_objects.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python + +# -*- coding: utf-8 -*- + +"""Script get_number_objects.py + +Get number of objects in a (last-run SExtractor) catalogue. + +:Author: Martin Kilbinger + +""" + +import sys +import copy +import glob + +from optparse import OptionParser +from astropy.io import fits + +from shapepipe.pipeline.run_log import get_last_dir +from shapepipe.utilities import cfis + + +class param: + """General class to store (default) variables""" + def __init__(self, **kwds): + self.__dict__.update(kwds) + + def print(self, **kwds): + print(self.__dict__) + + def var_list(self, **kwds): + return vars(self) + + +def params_default(): + """Set default parameter values. + + Returns + ------- + class param + parameter values + + """ + p_def = param( + input_path='.', + input_name_base='final_cat', + hdu_num=1, + ) + + return p_def + + +def parse_options(p_def): + """Parse command line options. + + Parameters + ---------- + p_def: class param + parameter values + + Returns + ------- + list + command line options + command line str + + """ + usage = "%prog [OPTIONS]" + parser = OptionParser(usage=usage) + + # IO + parser.add_option( + '-i', + '--input_path', + dest='input_path', + type='string', + default=p_def.input_path, + help=f'input path, default=\'{p_def.input_path}\'' + ) + parser.add_option( + '-n', + '--input_name_base', + dest='input_name_base', + type='string', + default=p_def.input_name_base, + help=f'input name base, default=\'{p_def.input_name_base}\'' + ) + parser.add_option( + '-l', + '--list_tile_ID_path', + dest='tile_ID_list_path', + type='string', + default=None, + help=f'tile ID list, default: Use all data in input files' + ) + + # Control + parser.add_option( + '-p', + '--param_path', + dest='param_path', + type='string', + default=None, + help='parameter file path, default=None' + ) + + parser.add_option( + '', + '--hdu_num', + dest='hdu_num', + type='int', + default=p_def.hdu_num, + help=f'input HDU number, default=\'{p_def.hdu_num}\'' + ) + + parser.add_option( + '-v', + '--verbose', + dest='verbose', + action='store_true', + help='verbose output' + ) + + options, args = parser.parse_args() + + return options, args + + +def check_options(options): + """Check command line options. + + Parameters + ---------- + options: tuple + Command line options + + Returns + ------- + bool + Result of option check. False if invalid option value. + + """ + return True + + +def update_param(p_def, options): + """Return default parameter, updated and complemented according to options. + + Parameters + ---------- + p_def: class param + parameter values + optiosn: tuple + command line options + + Returns + ------- + class param + updated paramter values + + """ + param = copy.copy(p_def) + + # Update keys in param according to options values + for key in vars(param): + if key in vars(options): + setattr(param, key, getattr(options, key)) + + # Add remaining keys from options to param + for key in vars(options): + if not key in vars(param): + setattr(param, key, getattr(options, key)) + + # Do extra stuff if necessary + + return param + + +def read_param_file(path, verbose=False): + """Return parameter list read from file + + Parameters + ---------- + path: str + input file name + verbose: bool, optional, default=False + verbose output if True + + Returns + ------- + list of str + parameter names + + """ + param_list = [] + + if path: + + with open(path) as f: + for line in f: + if line.startswith('#'): + continue + entry = line.rstrip() + if not entry or entry == '': + continue + param_list.append(entry) + + if verbose: + if len(param_list) > 0: + print(f'Copying {len(param_list)} columns', end='') + else: + print('Copying all columns', end='') + print(' into merged catalogue') + + # Check for multiples + multiples = [] + for param in param_list: + if param_list.count(param) > 1: + multiples.append(param) + + if len(multiples) > 0: + print('The following parameters are more than one times ' + 'in the parameter file: ', end='') + for m in multiples: + print(m, end=' ') + print() + raise ValueError('Multiple identical keys found') + + return param_list + + +def get_data(path, hdu_num, param_list): + """Return data of selected columns from FITS file. + + Parameters + ---------- + path: str + input file name + hdu_num: int + HDU number + param_list: list of str + parameters to be extracted. If none, copy + all columns + + Returns + ------- + numpy array + data columns + + """ + hdu_list = fits.open(path) + hdu = hdu_list[hdu_num] + + if param_list: + cols = [] + for p in param_list: + cols.append(hdu.columns[p]) + coldefs = fits.ColDefs(cols) + hdu_new = fits.BinTableHDU.from_columns(coldefs) + d = hdu_new.data + else: + d = hdu.data + + return d + + +def main(argv=None): + + # Set default parameters + p_def = params_default() + + # Command line options + options, args = parse_options(p_def) + + if check_options(options) is False: + return 1 + + param = update_param(p_def, options) + + # Save command line arguments to log file + f_log = cfis.log_command(argv, close_no_return=False) + + module = 'sextractor_runner_run_1' + pattern = 'sexcat' + run_log_file = 'output/log_run_sp.txt' + last_dir = get_last_dir(run_log_file, module) + + file_list = glob.glob(f'{last_dir}/{pattern}*.fits') + if len(file_list) == 0: + raise ValueError(f'No files {last_dir}/{pattern}*.fits found') + + n_obj = 0 + hdu_no = -1 + for fpath in file_list: + hdu_list = fits.open(fpath) + header = hdu_list[-1].header + n_obj += int(header['NAXIS2']) + + n_obj = int(n_obj / len(file_list)) + + print(n_obj) + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) diff --git a/scripts/sh/job_sp.bash b/scripts/sh/job_sp.bash index 6cbb687e7..84cea9bab 100755 --- a/scripts/sh/job_sp.bash +++ b/scripts/sh/job_sp.bash @@ -27,7 +27,7 @@ config_dir=$VM_HOME/shapepipe/example/cfis psf='mccd' retrieve='vos' results='cosmostat/kilbinger/results_v1' -nsh_step=3200 +nsh_step=-1 nsh_max=-1 nsh_jobs=8 @@ -56,7 +56,7 @@ usage="Usage: $(basename "$0") [OPTIONS] TILE_ID_1 [TILE_ID_2 [...]] \tnumber of shape measurement parallel jobs, default=$nsh_jobs\n --nsh_step NSTEP\n \tnumber of objects per parallel shape module call, \n - \t default: $nsh_step\n + \t default: optimal number is computed\n --nsh_max NMAX\n \tmax number of objects per parallel shape module call, \n \t default: unlimited; has precedent over --nsh_step\n @@ -362,6 +362,11 @@ if [[ $do_job != 0 ]]; then ### Prepare config files mkdir -p $SP_CONFIG_MOD n_min=0 + if [[ $nsh_step == -1 ]]; then + n_obj=`get_number_objects.py` + nsh_step=`echo "$(($n_obj/$nsh_jobs))"` + fi + n_max=$((nsh_step - 1)) for k in $(seq 1 $nsh_jobs); do cat $SP_CONFIG/config_tile_Ng_template.ini | \ From 01f284885917df2572b5e97a3ddb247b472022dd Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 16 Nov 2022 09:26:36 +0100 Subject: [PATCH 07/41] Ext star (#593) * fixed typo in variable name * config file vignet runner output fixed * typo in make_cat config ini file fixed * debugging ext stats in mask * mask config files for ext stars * external star cat as option in job_sp * mask config file names fixed * added back comment to pass tests * passing tests --- ...nfig_MaMa.ini => config_MaMa_onthefly.ini} | 4 +- example/cfis/config_MaMa_save.ini | 109 ++++++++++++++++++ .../{config.mask => config_onthefly.mask} | 0 example/cfis/config_save.mask | 86 ++++++++++++++ ...ig_tile.mask => config_tile_onthefly.mask} | 0 example/cfis/config_tile_save.mask | 90 +++++++++++++++ scripts/python/create_star_cat.py | 109 +++++++++--------- scripts/sh/job_sp.bash | 47 ++++++-- 8 files changed, 382 insertions(+), 63 deletions(-) rename example/cfis/{config_MaMa.ini => config_MaMa_onthefly.ini} (95%) create mode 100644 example/cfis/config_MaMa_save.ini rename example/cfis/{config.mask => config_onthefly.mask} (100%) create mode 100644 example/cfis/config_save.mask rename example/cfis/{config_tile.mask => config_tile_onthefly.mask} (100%) create mode 100644 example/cfis/config_tile_save.mask diff --git a/example/cfis/config_MaMa.ini b/example/cfis/config_MaMa_onthefly.ini similarity index 95% rename from example/cfis/config_MaMa.ini rename to example/cfis/config_MaMa_onthefly.ini index cc4b7f9c4..bde813940 100644 --- a/example/cfis/config_MaMa.ini +++ b/example/cfis/config_MaMa_onthefly.ini @@ -69,7 +69,7 @@ FILE_PATTERN = CFIS_image, CFIS_weight FILE_EXT = .fits, .fits # Path of mask config file -MASK_CONFIG_PATH = $SP_CONFIG/config_tile.mask +MASK_CONFIG_PATH = $SP_CONFIG/config_tile_onthefly.mask # External mask file flag, use if True, otherwise ignore USE_EXT_FLAG = False @@ -92,7 +92,7 @@ INPUT_DIR = last:split_exp_runner NUMBERING_SCHEME = -0000000-0 # Path of mask config file -MASK_CONFIG_PATH = $SP_CONFIG/config.mask +MASK_CONFIG_PATH = $SP_CONFIG/config_onthefly.mask # External mask file flag, use if True, otherwise ignore USE_EXT_FLAG = True diff --git a/example/cfis/config_MaMa_save.ini b/example/cfis/config_MaMa_save.ini new file mode 100644 index 000000000..4bd1b00ef --- /dev/null +++ b/example/cfis/config_MaMa_save.ini @@ -0,0 +1,109 @@ +# ShapePipe configuration file for masking of tiles and exposures + + +## Default ShapePipe options +[DEFAULT] + +# verbose mode (optional), default: True, print messages on terminal +VERBOSE = True + +# Name of run (optional) default: shapepipe_run +RUN_NAME = run_sp_MaMa + +# Add date and time to RUN_NAME, optional, default: False +; RUN_DATETIME = False + + +## ShapePipe execution options +[EXECUTION] + +# Module name, single string or comma-separated list of valid module runner names +MODULE = mask_runner, mask_runner + +# Parallel processing mode, SMP or MPI +MODE = SMP + + +## ShapePipe file handling options +[FILE] + +# Log file master name, optional, default: shapepipe +LOG_NAME = log_sp + +# Runner log file name, optional, default: shapepipe_runs +RUN_LOG_NAME = log_run_sp + +# Input directory, containing input files, single string or list of names +INPUT_DIR = . + +# Output directory +OUTPUT_DIR = $SP_RUN/output + + +## ShapePipe job handling options +[JOB] + +# Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial +SMP_BATCH_SIZE = 8 + +# Timeout value (optional), default is None, i.e. no timeout limit applied +TIMEOUT = 96:00:00 + + +## Module options + +### Mask tiles +[MASK_RUNNER_RUN_1] + +# Input directory, containing input files, single string or list of names +INPUT_DIR = last:get_images_runner_run_1, last:uncompress_fits_runner, star_cat_tiles + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# Input file pattern(s), list of strings with length matching number of expected input file types +# Cannot contain wild cards +FILE_PATTERN = CFIS_image, CFIS_weight, star_cat + +# FILE_EXT (optional) list of string extensions to identify input files +FILE_EXT = .fits, .fits, .cat + +# Path of mask config file +MASK_CONFIG_PATH = $SP_CONFIG/config_tile_save.mask + +# External mask file flag, use if True, otherwise ignore +USE_EXT_FLAG = False + +# External star catalogue flag, use external cat if True, +# obtain from online catalogue if False +USE_EXT_STAR = True + +# File name suffix for the output flag files (optional) +PREFIX = pipeline + +### Mask exposures +[MASK_RUNNER_RUN_2] + +# Parent module +INPUT_DIR = last:split_exp_runner, star_cat_exp + +# Update numbering convention, accounting for HDU number of +# single-exposure single-HDU files +NUMBERING_SCHEME = -0000000-0 + +FILE_PATTERN = image, weight, flag, star_cat + +FILE_EXT = .fits, .fits, .fits, .cat + +# Path of mask config file +MASK_CONFIG_PATH = $SP_CONFIG/config_save.mask + +# External mask file flag, use if True, otherwise ignore +USE_EXT_FLAG = True + +# External star catalogue flag, use external cat if True, +# obtain from online catalogue if False +USE_EXT_STAR = True + +# File name suffix for the output flag files (optional) +PREFIX = pipeline diff --git a/example/cfis/config.mask b/example/cfis/config_onthefly.mask similarity index 100% rename from example/cfis/config.mask rename to example/cfis/config_onthefly.mask diff --git a/example/cfis/config_save.mask b/example/cfis/config_save.mask new file mode 100644 index 000000000..887110ff5 --- /dev/null +++ b/example/cfis/config_save.mask @@ -0,0 +1,86 @@ +# Mask module configuration file for single-exposure images + +## Paths to executables +[PROGRAM_PATH] + +WW_PATH = ww +WW_CONFIG_FILE = $SP_CONFIG/mask_default/default.ww + +# Indicate cds client executable if no external star catalogue is available +# (e.g. no internet access on run nodes) +#CDSCLIENT_PATH = findgsc2.2 + + +## Border mask +[BORDER_PARAMETERS] + +BORDER_MAKE = True + +BORDER_WIDTH = 50 +BORDER_FLAG_VALUE = 4 + + +## Halo mask +[HALO_PARAMETERS] + +HALO_MAKE = True + +HALO_MASKMODEL_PATH = $SP_CONFIG/mask_default/halo_mask.reg +HALO_MAG_LIM = 13. +HALO_SCALE_FACTOR = 0.05 +HALO_MAG_PIVOT = 13.8 +HALO_FLAG_VALUE = 2 +HALO_REG_FILE = halo.reg + + +## Diffraction spike mask +[SPIKE_PARAMETERS] + +SPIKE_MAKE = True + +SPIKE_MASKMODEL_PATH = $SP_CONFIG/mask_default/MEGAPRIME_star_i_13.8.reg +SPIKE_MAG_LIM = 18. +SPIKE_SCALE_FACTOR = 0.3 +SPIKE_MAG_PIVOT = 13.8 +SPIKE_FLAG_VALUE = 128 +SPIKE_REG_FILE = spike.reg + + +## Messier mask +[MESSIER_PARAMETERS] + +MESSIER_MAKE = True + +MESSIER_CAT_PATH = $SP_CONFIG/mask_default/Messier_catalog_updated.fits +MESSIER_SIZE_PLUS = 0. +MESSIER_FLAG_VALUE = 16 + + +## NGC mask +[NGC_PARAMETERS] + +NGC_MAKE = True + +NGC_CAT_PATH = $SP_CONFIG/mask_default/ngc_cat.fits +NGC_SIZE_PLUS = 0. +NGC_FLAG_VALUE = 32 + + + +## Missing data parameters +[MD_PARAMETERS] + +MD_MAKE = False + +MD_THRESH_FLAG = 0.3 +MD_THRESH_REMOVE = 0.75 +MD_REMOVE = False + + +## Other parameters +[OTHER] + +TEMP_DIRECTORY = .temp + +KEEP_REG_FILE = False +KEEP_INDIVIDUAL_MASK = False diff --git a/example/cfis/config_tile.mask b/example/cfis/config_tile_onthefly.mask similarity index 100% rename from example/cfis/config_tile.mask rename to example/cfis/config_tile_onthefly.mask diff --git a/example/cfis/config_tile_save.mask b/example/cfis/config_tile_save.mask new file mode 100644 index 000000000..4b5fbb7f8 --- /dev/null +++ b/example/cfis/config_tile_save.mask @@ -0,0 +1,90 @@ +# Mask module config file for tiles + +## Paths to executables +[PROGRAM_PATH] + +WW_PATH = ww +WW_CONFIG_FILE = $SP_CONFIG/mask_default/default.ww + +# Indicate cds client executable if no external star catalogue is available +# (e.g. no internet access on run nodes) +#CDSCLIENT_PATH = findgsc2.2 + +## Border parameters +[BORDER_PARAMETERS] + +BORDER_MAKE = False + +BORDER_WIDTH = 0 +BORDER_FLAG_VALUE = 4 + + +## Halo parameters +[HALO_PARAMETERS] + +HALO_MAKE = True + +HALO_MASKMODEL_PATH = $SP_CONFIG/mask_default/halo_mask.reg +HALO_MAG_LIM = 13. +HALO_SCALE_FACTOR = 0.05 +HALO_MAG_PIVOT = 13.8 +HALO_FLAG_VALUE = 2 +HALO_REG_FILE = halo.reg + + +## Diffraction pike parameters +[SPIKE_PARAMETERS] + +SPIKE_MAKE = True + +SPIKE_MASKMODEL_PATH = $SP_CONFIG/mask_default/MEGAPRIME_star_i_13.8.reg +SPIKE_MAG_LIM = 18. +SPIKE_SCALE_FACTOR = 0.3 +SPIKE_MAG_PIVOT = 13.8 +SPIKE_FLAG_VALUE = 128 +SPIKE_REG_FILE = spike.reg + + +## Messier parameters +[MESSIER_PARAMETERS] + +MESSIER_MAKE = True + +MESSIER_CAT_PATH = $SP_CONFIG/mask_default/Messier_catalog_updated.fits +MESSIER_PIXEL_SCALE = 0.187 +MESSIER_SIZE_PLUS = 0. +MESSIER_FLAG_VALUE = 16 + +## NGC mask +[NGC_PARAMETERS] + +NGC_MAKE = True + +NGC_CAT_PATH = $SP_CONFIG/mask_default/ngc_cat.fits +NGC_SIZE_PLUS = 0. +NGC_FLAG_VALUE = 32 + + +## External flag +[EXTERNAL_FLAG] + +EF_MAKE = False + + +## Missing data parameters +[MD_PARAMETERS] + +MD_MAKE = False + +MD_THRESH_FLAG = 0.3 +MD_THRESH_REMOVE = 0.75 +MD_REMOVE = False + + +## Other parameters +[OTHER] + +KEEP_REG_FILE = False +KEEP_INDIVIDUAL_MASK = False + +TEMP_DIRECTORY = .temp_tiles diff --git a/scripts/python/create_star_cat.py b/scripts/python/create_star_cat.py index feecb7209..2c87d3f8d 100755 --- a/scripts/python/create_star_cat.py +++ b/scripts/python/create_star_cat.py @@ -4,31 +4,30 @@ """Script create_star_cat.py -Create reference star catalogue for masking of -bright stars and diffraction spikes +:Description: Create reference star catalogue for masking of +bright star halos and diffraction spikes :Authors: Axel Guinot, Martin Kilbinger -:Date: 2019, 2020 - -:Package: ShapePipe """ -from shapepipe.pipeline.execute import execute +import re +import os +import sys import numpy as np + from astropy.coordinates import SkyCoord from astropy.wcs import WCS from astropy.io import fits from astropy import units as u -import re -import os -import sys + +from shapepipe.pipeline.execute import execute def _get_wcs(header): - """Get WCS + """Get WCS. Compute the astropy WCS from header manually. (The purpose of this is to avoid possible incompatibility on distortion @@ -41,10 +40,10 @@ def _get_wcs(header): Returns ------- - final_wcs : astropy.wcs.WCS + astropy.wcs.WCS WCS object - """ + """ final_wcs = WCS(naxis=2) final_wcs.wcs.ctype = [header['CTYPE1'], header['CTYPE2']] try: @@ -53,14 +52,16 @@ def _get_wcs(header): final_wcs.wcs.cunit = ['deg', 'deg'] final_wcs.wcs.crpix = [header['CRPIX1'], header['CRPIX2']] final_wcs.wcs.crval = [header['CRVAL1'], header['CRVAL2']] - final_wcs.wcs.cd = [[header['CD1_1'], header['CD1_2']], - [header['CD2_1'], header['CD2_2']]] + final_wcs.wcs.cd = [ + [header['CD1_1'], header['CD1_2']], + [header['CD2_1'], header['CD2_2']] + ] return final_wcs def _get_image_radius(center, wcs): - """Get image radius + """Get Image Radius. Compute the diagonal distance of the image in arcmin. @@ -68,59 +69,68 @@ def _get_image_radius(center, wcs): ---------- center : numpy.ndarray Coordinates of the center of the image (in pixel) + wcs : astropy.wcs.WCS + WCS object Returns ------- float The diagonal distance of the image in arcmin. - """ + """ if center is None: - return SphereDist(self._fieldcenter['pix'], np.zeros(2))/60. + raise ValueError('center cannot be None') else: if type(center) is np.ndarray: - return SphereDist(center, np.zeros(2), wcs)/60. + return SphereDist(center, np.zeros(2), wcs) / 60.0 else: raise TypeError('center has to be a numpy.ndarray') def SphereDist(position1, position2, wcs): - """Compute spherical distance - - Compute spherical distance between 2 points. + """Sphere Dist. + + Compute distance between two points on the sphere. Parameters ---------- position1 : numpy.ndarray - [x,y] first point (in pixel) + [x,y], first point (in pixels) position2 : numpy.ndarray - [x,y] second point (in pixel) + [x,y], second point (in pixels) Returns ------- float - The distance in degree. + distance (in degrees) """ - if (type(position1) is not np.ndarray) & (type(position2) is not np.ndarray): - raise ValueError('Positions need to be a numpy.ndarray') + if ( + (type(position1) is not np.ndarray) + & (type(position2) is not np.ndarray) + ): + raise ValueError('Positions need to be of type numpy.ndarray') - p1 = (np.pi/180.)*np.hstack(wcs.all_pix2world(position1[0], position1[1], 1)) - p2 = (np.pi/180.)*np.hstack(wcs.all_pix2world(position2[0], position2[1], 1)) + rad2deg = np.pi / 180.0 + p1 = rad2deg * np.hstack(wcs.all_pix2world(position1[0], position1[1], 1)) + p2 = rad2deg * np.hstack(wcs.all_pix2world(position2[0], position2[1], 1)) dTheta = p1 - p2 dLong = dTheta[0] dLat = dTheta[1] - dist = 2*np.arcsin(np.sqrt(np.sin(dLat/2.)**2. + np.cos(p1[1])*np.cos(p2[1])*np.sin(dLong/2.)**2.)) + dist = 2 * np.arcsin( + np.sqrt(np.sin(dLat/2.0)**2 + np.cos(p1[1])*np.cos(p2[1])*np.sin(dLong/2.0)**2) + ) return dist*(180./np.pi)*3600. def find_stars(position, output_name, radius=None): - """Find stars + """Find Stars. - Return GSC (Guide Star Catalog) objects for a field with center (ra,dec) and radius r. + Return GSC (Guide Star Catalog) objects for a field with center + (ra,dec) and radius r. Parameters ---------- @@ -129,12 +139,7 @@ def find_stars(position, output_name, radius=None): radius : float Radius in which the query is done (in arcmin) - Returns - ------- - dict - Stars dicotionnary for GSC objects in the field. """ - ra = position[0] dec = position[1] @@ -145,22 +150,14 @@ def find_stars(position, output_name, radius=None): else: sign = '' - cmd_line = '{0} {1} {2}{3} -r {4} -n 1000000'.format('findgsc2.2', ra, sign, dec, radius) + cmd_line = f'findgsc2.2 {ra} {sign}{dec} -r {radius} -n 1000000' - # output=subprocess.check_output(cmd_line, shell=True) CDS_stdout, CDS_stderr = execute(cmd_line) output_file = open(output_name, 'w') output_file.write(CDS_stdout) output_file.close() - # if CDS_stderr != '': - # err = True - # return None - # - # # return self._make_star_cat(output.decode("utf-8")) - # return CDS_stdout - def main(input_dir, output_dir, kind): @@ -170,8 +167,6 @@ def main(input_dir, output_dir, kind): if 'image' not in f: continue - # img = fits.open(input_dir + '/' + f) - if kind == 'exp': list_ind = range(1, 41) else: @@ -184,12 +179,12 @@ def main(input_dir, output_dir, kind): else: exp_suff = '' - output_name = output_dir + '/star_cat' + re.split('image', os.path.splitext(f)[0])[1] + exp_suff + '.cat' + img_number = re.split('image', os.path.splitext(f)[0])[1] + output_name = f'{output_dir}/star_cat{img_number}{exp_suff}.cat' if os.path.isfile(output_name): continue - # h = img[ind].header h = fits.getheader(input_dir + '/' + f, ind) w = _get_wcs(h) @@ -197,11 +192,21 @@ def main(input_dir, output_dir, kind): img_shape = (h['NAXIS2'], h['NAXIS1']) img_center = np.array([img_shape[1]/2., img_shape[0]/2.]) wcs_center = w.all_pix2world([img_center], 1)[0] - astropy_center = SkyCoord(ra=wcs_center[0], dec=wcs_center[1], unit='deg') + astropy_center = SkyCoord( + ra=wcs_center[0], + dec=wcs_center[1], + unit='deg' + ) rad = _get_image_radius(img_center, w) - find_stars(np.array([astropy_center.ra.value, astropy_center.dec.value]), output_name, rad) + find_stars( + np.array([astropy_center.ra.value, astropy_center.dec.value]), + output_name, + rad + ) + + return 0 if __name__ == '__main__': @@ -218,11 +223,9 @@ def main(input_dir, output_dir, kind): except: output_path = '.' - # Temporary fix try: kind = argv[3] except: kind = '' main(input_path, output_path, kind) - diff --git a/scripts/sh/job_sp.bash b/scripts/sh/job_sp.bash index 84cea9bab..2b1ee0ecd 100755 --- a/scripts/sh/job_sp.bash +++ b/scripts/sh/job_sp.bash @@ -26,6 +26,7 @@ job=255 config_dir=$VM_HOME/shapepipe/example/cfis psf='mccd' retrieve='vos' +star_cat_for_mask='save' results='cosmostat/kilbinger/results_v1' nsh_step=-1 nsh_max=-1 @@ -50,6 +51,8 @@ usage="Usage: $(basename "$0") [OPTIONS] TILE_ID_1 [TILE_ID_2 [...]] \tPSF model, one in ['psfex'|'mccd'], default='$psf'\n -r, --retrieve METHOD\n \tmethod to retrieve images, one in ['vos'|'symlink]', default='$retrieve'\n + -s, --star_cat_for_mask\n + \tcatalogue for masking bright stars, allowed are 'onthefly' (default), 'save'\n -o, --output_dir\n \toutput (upload) directory on vos:cfis, default='$results'\n --nsh_jobs NJOB\n @@ -94,6 +97,10 @@ while [ $# -gt 0 ]; do retrieve="$2" shift ;; + -s|--star_cat_for_mask) + star_cat_for_mask="$2" + shift + ;; -o|--output_dir) results="$2" shift @@ -122,11 +129,23 @@ if [ "$psf" != "psfex" ] && [ "$psf" != "mccd" ]; then echo "PSF (option -p) needs to be 'psfex' or 'mccd'" exit 2 fi + +if [ "$star_cat_for_mask" != "onthefly" ] && [ "$star_cat_for_mask" != "save" ]; then + echo "Star cat for mask (option -s) needs to be 'onthefly' or 'save'" + exit 4 +fi + +if [ "$retrieve" != "vos" ] && [ "$retrieve" != "symlink" ]; then + echo "method to retrieve images (option -r) needs to be 'vos' or 'symlink'" + exit 5 +fi + n_tile=${#TILE_ARR[@]} if [ "$n_tile" == "0" ]; then echo "No tile ID given" exit 3 fi + if [ $nsh_max != -1 ]; then nsh_step=$nsh_max fi @@ -177,13 +196,13 @@ function command () { cmd=$1 str=$2 - #RED='\033[0;31m' - #GREEN='\033[0;32m' - #NC='\033[0m' # No Color + RED='\033[0;31m' + GREEN='\033[0;32m' + NC='\033[0m' # No Color # Color escape characters show up in log files - RED='' - GREEN='' - NC='' + #RED='' + #GREEN='' + #NC='' if [ $# == 2 ]; then @@ -287,6 +306,7 @@ mkdir -p $OUTPUT # Processing ## Retrieve config files and images (online if retrieve=vos) +## Retrieve and save star catalogues for masking (if star_cat_for_mask=save) (( do_job= $job & 1 )) if [[ $do_job != 0 ]]; then @@ -306,7 +326,18 @@ if [[ $do_job != 0 ]]; then fi ### Retrieve files - command_sp "shapepipe_run -c $SP_CONFIG/config_GitFeGie_$retrieve.ini" "Retrieve images" + #command_sp "shapepipe_run -c $SP_CONFIG/config_GitFeGie_$retrieve.ini" "Retrieve images" + + ### Retrieve and save star catalogues for masking + if [ "$star_cat_for_mask" == "save" ]; then + #### For tiles + mkdir $SP_RUN/star_cat_tiles + command_sp "create_star_cat $SP_RUN/output/run_sp_GitFeGie_*/get_images_runner_run_1/output $SP_RUN/star_cat_tiles" "Save star cats for masking (tile)" + + #### For single-exposures + mkdir $SP_RUN/star_cat_exp + command_sp "create_star_cat $SP_RUN/output/run_sp_GitFeGie_*/get_images_runner_run_2/output $SP_RUN/star_cat_exp exp" "Save star cats for masking (exp)" + fi fi @@ -327,7 +358,7 @@ fi if [[ $do_job != 0 ]]; then ### Mask tiles and exposures - command_sp "shapepipe_run -c $SP_CONFIG/config_MaMa.ini" "Run shapepipe (mask)" + command_sp "shapepipe_run -c $SP_CONFIG/config_MaMa_$star_cat_for_mask.ini" "Run shapepipe (mask)" fi From 37eddea251adaa9237a368ec2593012cbd4f7658 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 7 Dec 2022 12:29:44 +0100 Subject: [PATCH 08/41] candide qsub job example config file updated --- example/pbs/config_smp.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/pbs/config_smp.ini b/example/pbs/config_smp.ini index bb61e78f5..d47a8c9d6 100644 --- a/example/pbs/config_smp.ini +++ b/example/pbs/config_smp.ini @@ -2,7 +2,7 @@ ## ShapePipe execution options [EXECUTION] -MODULE = python_example, serial_example, execute_example +MODULE = python_example_runner, serial_example_runner, execute_example_runner MODE = smp ## ShapePipe file handling options @@ -16,8 +16,8 @@ SMP_BATCH_SIZE = 4 TIMEOUT = 00:01:35 ## Module options -[PYTHON_EXAMPLE] +[PYTHON_EXAMPLE_RUNNER] MESSAGE = The obtained value is: -[SERIAL_EXAMPLE] +[SERIAL_EXAMPLE_RUNNER] ADD_INPUT_DIR = $SPDIR/example/data/numbers, $SPDIR/example/data/letters From 703dc82a5d0df41cc6d83cc972c2cefe6e6a55f1 Mon Sep 17 00:00:00 2001 From: Fabian Hervas Date: Wed, 14 Dec 2022 15:27:34 +0100 Subject: [PATCH 09/41] get images file handling bug --- shapepipe/modules/get_images_package/get_images.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shapepipe/modules/get_images_package/get_images.py b/shapepipe/modules/get_images_package/get_images.py index f0a4220c6..9ee3da23e 100644 --- a/shapepipe/modules/get_images_package/get_images.py +++ b/shapepipe/modules/get_images_package/get_images.py @@ -62,7 +62,8 @@ def in2out_pattern(number): # remove letters in number number_final = re.sub('[a-zA-Z]', '', number_final) - + # make robust for more generalized file names + number_final = re.sub(r'_', '', number_final) return number_final From 788fc6d7f3bf01d568c149703210550cbabeec44 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 4 Jan 2023 11:35:23 +0100 Subject: [PATCH 10/41] test --- example/cfis/config_GitFeGie_symlink.ini | 4 +- scripts/sh/job_sp.bash | 13 +- .../modules/get_images_package/get_images.py | 25 ++- shapepipe/utilities/canfar.py | 190 ------------------ 4 files changed, 25 insertions(+), 207 deletions(-) delete mode 100644 shapepipe/utilities/canfar.py diff --git a/example/cfis/config_GitFeGie_symlink.ini b/example/cfis/config_GitFeGie_symlink.ini index bc39a1e02..f3ab3499f 100644 --- a/example/cfis/config_GitFeGie_symlink.ini +++ b/example/cfis/config_GitFeGie_symlink.ini @@ -66,7 +66,7 @@ NUMBERING_SCHEME = # Input path where original images are stored. Can be local path or vos url. # Single string or list of strings -INPUT_PATH = $HOME/astro/data/CFIS/tiles_DR2, $HOME/astro/data/CFIS/tiles_DR2 +INPUT_PATH = $SP_RUN/data_tiles, $SP_RUN/data_tiles # Input file pattern including tile number as dummy template INPUT_FILE_PATTERN = CFIS.000.000.r, CFIS.000.000.r.weight @@ -119,7 +119,7 @@ NUMBERING_SCHEME = -000-000 # Input path where original images are stored. Can be local path or vos url. # Single string or list of strings -INPUT_PATH = $HOME/astro/data/CFIS/pitcairn_DR2, $HOME/astro/data/CFIS/weights_DR2, $HOME/astro/data/CFIS/flags_DR2 +INPUT_PATH = $SP_RUN/data_exp, $SP_RUN/data_exp, $SP_RUN/data_exp # Input file pattern including tile number as dummy template INPUT_FILE_PATTERN = 000000, 000000.weight, 000000.flag diff --git a/scripts/sh/job_sp.bash b/scripts/sh/job_sp.bash index 2b1ee0ecd..b20abadd0 100755 --- a/scripts/sh/job_sp.bash +++ b/scripts/sh/job_sp.bash @@ -26,7 +26,7 @@ job=255 config_dir=$VM_HOME/shapepipe/example/cfis psf='mccd' retrieve='vos' -star_cat_for_mask='save' +star_cat_for_mask='onthefly' results='cosmostat/kilbinger/results_v1' nsh_step=-1 nsh_max=-1 @@ -50,19 +50,20 @@ usage="Usage: $(basename "$0") [OPTIONS] TILE_ID_1 [TILE_ID_2 [...]] -p, --psf MODEL\n \tPSF model, one in ['psfex'|'mccd'], default='$psf'\n -r, --retrieve METHOD\n - \tmethod to retrieve images, one in ['vos'|'symlink]', default='$retrieve'\n + \tmethod to retrieve images, allowed are 'vos', 'symlink', default='$retrieve'\n -s, --star_cat_for_mask\n - \tcatalogue for masking bright stars, allowed are 'onthefly' (default), 'save'\n + \tcatalogue for masking bright stars, allowed are 'onthefly', 'save',\n + \tdefault is '${star_cat_for_mask}'\n -o, --output_dir\n \toutput (upload) directory on vos:cfis, default='$results'\n --nsh_jobs NJOB\n \tnumber of shape measurement parallel jobs, default=$nsh_jobs\n --nsh_step NSTEP\n \tnumber of objects per parallel shape module call, \n - \t default: optimal number is computed\n + \tdefault: optimal number is computed\n --nsh_max NMAX\n \tmax number of objects per parallel shape module call, \n - \t default: unlimited; has precedent over --nsh_step\n + \tdefault: unlimited; has precedent over --nsh_step\n TILE_ID_i\n \ttile ID(s), e.g. 283.247 214.242\n " @@ -326,7 +327,7 @@ if [[ $do_job != 0 ]]; then fi ### Retrieve files - #command_sp "shapepipe_run -c $SP_CONFIG/config_GitFeGie_$retrieve.ini" "Retrieve images" + command_sp "shapepipe_run -c $SP_CONFIG/config_GitFeGie_$retrieve.ini" "Retrieve images" ### Retrieve and save star catalogues for masking if [ "$star_cat_for_mask" == "save" ]; then diff --git a/shapepipe/modules/get_images_package/get_images.py b/shapepipe/modules/get_images_package/get_images.py index f0a4220c6..ff65ec1cb 100644 --- a/shapepipe/modules/get_images_package/get_images.py +++ b/shapepipe/modules/get_images_package/get_images.py @@ -185,14 +185,19 @@ def process(self, input_dir, output_dir): input_dir, use_output_file_pattern=False ) - all_outputs = self.get_file_list( + all_outputs_orig = self.get_file_list( + image_number_list, + output_dir, + use_output_file_pattern=False + ) + all_outputs_renamed = self.get_file_list( image_number_list, output_dir, use_output_file_pattern=True ) # Retrieve files - self.retrieve(all_inputs, all_outputs) + self.retrieve(all_inputs, all_outputs_orig, all_outputs_renamed) def get_file_list( self, @@ -260,7 +265,7 @@ def get_file_list( return list_all_files - def retrieve(self, all_inputs, all_outputs): + def retrieve(self, all_inputs, all_outputs_orig, all_outputs_renamed): """Retrieve. Retrieve all files. @@ -273,10 +278,10 @@ def retrieve(self, all_inputs, all_outputs): Output file paths, one list for each input file type """ - for in_per_type, out_per_type in zip(all_inputs, all_outputs): + for in_per_type, out_per_type_orig, out_per_type_renamed in zip(all_inputs, all_outputs_orig, all_outputs_renamed): for idx in range(len(in_per_type)): if self._check_existing_dir: - out_base = os.path.basename(out_per_type[idx]) + out_base = os.path.basename(out_per_type_orig[idx]) path = glob.glob( f'{self._check_existing_dir}/**/{out_base}', recursive=True, @@ -300,9 +305,9 @@ def retrieve(self, all_inputs, all_outputs): + f' {self._check_existing_dir},' + ' downloading images' ) - self.retrieve_one(in_per_type[idx], out_per_type[idx]) + self.retrieve_one(in_per_type[idx], out_per_type_orig[idx], out_per_type_renamed[idx]) - def retrieve_one(self, in_path, out_path): + def retrieve_one(self, in_path, out_path_orig, out_path_renamed): """Retrieve One. Retrieve one file. @@ -322,7 +327,7 @@ def retrieve_one(self, in_path, out_path): for opt in self._retrieve_options.split(' '): sys.argv.append(opt) sys.argv.append(in_path) - sys.argv.append(out_path) + sys.argv.append(out_path_orig) log_cmd = ' '.join(sys.argv) vcp = vosHandler('vcp') @@ -346,6 +351,8 @@ def retrieve_one(self, in_path, out_path): sys.argv = None + os.symlink(out_path_orig, out_path_renamed) + elif self._retrieve_method == 'symlink': src = in_path @@ -356,7 +363,7 @@ def retrieve_one(self, in_path, out_path): f'No input file found corresponding to \'{src}\'' ) - dst = out_path + dst = out_path_renamed for src in all_src: if os.path.isdir(dst): # OUTPUT_FILE_PATTERN is '*', so dst is not regular file diff --git a/shapepipe/utilities/canfar.py b/shapepipe/utilities/canfar.py deleted file mode 100644 index bf67c8574..000000000 --- a/shapepipe/utilities/canfar.py +++ /dev/null @@ -1,190 +0,0 @@ -"""CANFAR TOOLS. - -This module defines methods for managing CANFAR specific actions. - -:Author: Samuel Farrens - Martin Kilbinger - -""" - -import os -import sys -from contextlib import redirect_stdout -from io import StringIO - -try: - import vos.commands as vosc -except ImportError: # pragma: no cover - import_fail = True -else: - import_fail = False - - -class vosError(Exception): - """VOS Error. - - Generic error that is raised by the vosHandler. - - """ - - pass - - -class vosHandler: - """VOS Handler. - - This class manages the use of VOS commands. - - Parameters - ---------- - command : str - VOS command name - - """ - - def __init__(self, command): - - self._check_vos_install() - self._avail_commands = tuple(vosc.__all__) - self.command = command - - @staticmethod - def _check_vos_install(): - """Check VOS Install. - - Check if VOS is correctly installed. - - Raises - ------ - ImportError - if vos package cannot be imported - - """ - if import_fail: - raise ImportError( - 'vos package not found, re-install ShapePipe ' - + 'with \'./install_shapepipe --vos\'' - ) - - @property - def command(self): - """Set Command. - - This method sets the VOS command property. - - Raises - ------ - ValueError - if value is not valid vos command - - """ - return self._command - - @command.setter - def command(self, value): - - if value not in self._avail_commands: - raise ValueError( - f'vos command must be one of {self._avail_commands}' - ) - - self._command = getattr(vosc, value) - - def __call__(self, *args, **kwargs): - """Call Method. - - This method allows class instances to be called as functions. - - Raises - ------ - vosError - if error in vos command occurs - - """ - try: - self._command() - - except Exception: - raise vosError( - f'Error in VOs command: {self._command.__name__}' - ) - - -def download(source, target, verbose=False): - """Download. - - Download file from vos. - - Parameters - ---------- - source : str - source path on vos - target : str - target path - verbose : bool, optional, default=False - verbose output if True - - Returns - ------- - status : bool - status, True/False or success/failure - - """ - cmd = 'vcp' - - if not os.path.exists(target): - sys.argv = [cmd, source, target] - if verbose: - print(f'Downloading file {source} to {target}...') - vcp = vosHandler(cmd) - - vcp() - if verbose: - print('Download finished.') - else: - if verbose: - print(f'Target file {target} exists, skipping download.') - - -def dir_list(path, verbose=False): - """Set Directory List. - - List content of path on vos. - - Parameters - ---------- - path : str - path on vos, starts with 'vos:cfis/...' - verbose : bool, optional, default=False - verbose output if True - - Raises - ------ - HTTPError, KeyError - if error occurs during vos command - - Returns - ------- - vls_out : array of str - file or directory at path - - """ - cmd = 'vls' - sys.argv = [cmd, path] - vls = vosHandler(cmd) - - if verbose: - print('Getting vos directory content from vls...') - - f = StringIO() - - try: - with redirect_stdout(f): - vls() - except Exception: - print('Error during vls command') - raise - - vls_out = f.getvalue() - - return vls_out.split('\n') From b37b8d0ec63692217fe30b0e664f23a4b4f93dfb Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 17 Jan 2023 16:44:04 +0100 Subject: [PATCH 11/41] code style --- .../modules/get_images_package/get_images.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/shapepipe/modules/get_images_package/get_images.py b/shapepipe/modules/get_images_package/get_images.py index ff65ec1cb..57c62a6e2 100644 --- a/shapepipe/modules/get_images_package/get_images.py +++ b/shapepipe/modules/get_images_package/get_images.py @@ -278,7 +278,11 @@ def retrieve(self, all_inputs, all_outputs_orig, all_outputs_renamed): Output file paths, one list for each input file type """ - for in_per_type, out_per_type_orig, out_per_type_renamed in zip(all_inputs, all_outputs_orig, all_outputs_renamed): + for in_per_type, out_per_type_orig, out_per_type_renamed in zip( + all_inputs, + all_outputs_orig, + all_outputs_renamed + ): for idx in range(len(in_per_type)): if self._check_existing_dir: out_base = os.path.basename(out_per_type_orig[idx]) @@ -305,7 +309,11 @@ def retrieve(self, all_inputs, all_outputs_orig, all_outputs_renamed): + f' {self._check_existing_dir},' + ' downloading images' ) - self.retrieve_one(in_per_type[idx], out_per_type_orig[idx], out_per_type_renamed[idx]) + self.retrieve_one( + in_per_type[idx], + out_per_type_orig[idx], + out_per_type_renamed[idx] + ) def retrieve_one(self, in_path, out_path_orig, out_path_renamed): """Retrieve One. @@ -333,6 +341,7 @@ def retrieve_one(self, in_path, out_path_orig, out_path_renamed): vcp = vosHandler('vcp') self._w_log.info(log_cmd) + # Download file from VOSpace attempt = 0 while attempt < self._n_try: try: @@ -351,6 +360,8 @@ def retrieve_one(self, in_path, out_path_orig, out_path_renamed): sys.argv = None + # Create symbolic link to downloaded file with + # link name in ShapePipe numbering format os.symlink(out_path_orig, out_path_renamed) elif self._retrieve_method == 'symlink': From f932357f2636d9a1b3d27d764a05523e806a15a0 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 17 Jan 2023 16:46:50 +0100 Subject: [PATCH 12/41] passing tests --- .../modules/get_images_package/get_images.py | 2 +- shapepipe/utilities/canfar.py | 190 ++++++++++++++++++ 2 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 shapepipe/utilities/canfar.py diff --git a/shapepipe/modules/get_images_package/get_images.py b/shapepipe/modules/get_images_package/get_images.py index 57c62a6e2..74bc18f13 100644 --- a/shapepipe/modules/get_images_package/get_images.py +++ b/shapepipe/modules/get_images_package/get_images.py @@ -361,7 +361,7 @@ def retrieve_one(self, in_path, out_path_orig, out_path_renamed): sys.argv = None # Create symbolic link to downloaded file with - # link name in ShapePipe numbering format + # link name in ShapePipe numbering format os.symlink(out_path_orig, out_path_renamed) elif self._retrieve_method == 'symlink': diff --git a/shapepipe/utilities/canfar.py b/shapepipe/utilities/canfar.py new file mode 100644 index 000000000..bf67c8574 --- /dev/null +++ b/shapepipe/utilities/canfar.py @@ -0,0 +1,190 @@ +"""CANFAR TOOLS. + +This module defines methods for managing CANFAR specific actions. + +:Author: Samuel Farrens + Martin Kilbinger + +""" + +import os +import sys +from contextlib import redirect_stdout +from io import StringIO + +try: + import vos.commands as vosc +except ImportError: # pragma: no cover + import_fail = True +else: + import_fail = False + + +class vosError(Exception): + """VOS Error. + + Generic error that is raised by the vosHandler. + + """ + + pass + + +class vosHandler: + """VOS Handler. + + This class manages the use of VOS commands. + + Parameters + ---------- + command : str + VOS command name + + """ + + def __init__(self, command): + + self._check_vos_install() + self._avail_commands = tuple(vosc.__all__) + self.command = command + + @staticmethod + def _check_vos_install(): + """Check VOS Install. + + Check if VOS is correctly installed. + + Raises + ------ + ImportError + if vos package cannot be imported + + """ + if import_fail: + raise ImportError( + 'vos package not found, re-install ShapePipe ' + + 'with \'./install_shapepipe --vos\'' + ) + + @property + def command(self): + """Set Command. + + This method sets the VOS command property. + + Raises + ------ + ValueError + if value is not valid vos command + + """ + return self._command + + @command.setter + def command(self, value): + + if value not in self._avail_commands: + raise ValueError( + f'vos command must be one of {self._avail_commands}' + ) + + self._command = getattr(vosc, value) + + def __call__(self, *args, **kwargs): + """Call Method. + + This method allows class instances to be called as functions. + + Raises + ------ + vosError + if error in vos command occurs + + """ + try: + self._command() + + except Exception: + raise vosError( + f'Error in VOs command: {self._command.__name__}' + ) + + +def download(source, target, verbose=False): + """Download. + + Download file from vos. + + Parameters + ---------- + source : str + source path on vos + target : str + target path + verbose : bool, optional, default=False + verbose output if True + + Returns + ------- + status : bool + status, True/False or success/failure + + """ + cmd = 'vcp' + + if not os.path.exists(target): + sys.argv = [cmd, source, target] + if verbose: + print(f'Downloading file {source} to {target}...') + vcp = vosHandler(cmd) + + vcp() + if verbose: + print('Download finished.') + else: + if verbose: + print(f'Target file {target} exists, skipping download.') + + +def dir_list(path, verbose=False): + """Set Directory List. + + List content of path on vos. + + Parameters + ---------- + path : str + path on vos, starts with 'vos:cfis/...' + verbose : bool, optional, default=False + verbose output if True + + Raises + ------ + HTTPError, KeyError + if error occurs during vos command + + Returns + ------- + vls_out : array of str + file or directory at path + + """ + cmd = 'vls' + sys.argv = [cmd, path] + vls = vosHandler(cmd) + + if verbose: + print('Getting vos directory content from vls...') + + f = StringIO() + + try: + with redirect_stdout(f): + vls() + except Exception: + print('Error during vls command') + raise + + vls_out = f.getvalue() + + return vls_out.split('\n') From 63cb3f024644eac53b255e462cea8b603813496e Mon Sep 17 00:00:00 2001 From: Fabian Hervas Date: Thu, 26 Jan 2023 17:41:47 +0100 Subject: [PATCH 13/41] prefix find_exp_runner --- shapepipe/modules/find_exposures_package/find_exposures.py | 5 +++-- shapepipe/modules/find_exposures_runner.py | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/shapepipe/modules/find_exposures_package/find_exposures.py b/shapepipe/modules/find_exposures_package/find_exposures.py index 494118e76..4396ec151 100644 --- a/shapepipe/modules/find_exposures_package/find_exposures.py +++ b/shapepipe/modules/find_exposures_package/find_exposures.py @@ -28,12 +28,13 @@ class FindExposures(): """ - def __init__(self, img_tile_path, output_path, w_log, colnum): + def __init__(self, img_tile_path, output_path, w_log, colnum, prefix): self._img_tile_path = img_tile_path self._output_path = output_path self._w_log = w_log self._colnum = colnum + self.prefix = prefix def process(self): """Process. @@ -92,7 +93,7 @@ def get_exposure_list(self): ) exp_name = pattern_match.group(1) - + exp_name = exp_name.removeprefix(self.prefix) # LSB exposure names have 's', header still says 'p' # exp_name = re.sub(r'p', 's', exp_name) diff --git a/shapepipe/modules/find_exposures_runner.py b/shapepipe/modules/find_exposures_runner.py index 66a80f4f0..4fc7d3a8a 100644 --- a/shapepipe/modules/find_exposures_runner.py +++ b/shapepipe/modules/find_exposures_runner.py @@ -35,12 +35,15 @@ def find_exposures_runner( # Give clumn number for exposure name in fits header colnum = config.getint(module_config_sec, 'COLNUM') + # Give the prefix of exposures + exp_prefix = config.get(module_config_sec, 'EXP_PREFIX') # Create find exposures class instance find_exp_inst = find_exposures.FindExposures( input_file_name, output_path, w_log, colnum, + exp_prefix, ) # Run processing From d04ee32b7961138a29a2c9eb7f2371765d4a5d83 Mon Sep 17 00:00:00 2001 From: Fabian Hervas Date: Thu, 26 Jan 2023 18:31:26 +0100 Subject: [PATCH 14/41] fix uint32, still error --- shapepipe/modules/mask_package/mask.py | 1 + 1 file changed, 1 insertion(+) diff --git a/shapepipe/modules/mask_package/mask.py b/shapepipe/modules/mask_package/mask.py index 17e61b847..fad3a0187 100644 --- a/shapepipe/modules/mask_package/mask.py +++ b/shapepipe/modules/mask_package/mask.py @@ -1179,6 +1179,7 @@ def _build_final_mask( ) external_flag.open() if final_mask is not None: + final_mask=final_mask.astype(np.int16, copy=False) final_mask += external_flag.get_data()[:, :] else: final_mask = external_flag.get_data()[:, :] From c50f202534892e1aca2c5309e90be0d3f4bcf784 Mon Sep 17 00:00:00 2001 From: Samuel Farrens Date: Wed, 15 Feb 2023 13:41:20 +0100 Subject: [PATCH 15/41] updated CI set up --- .github/workflows/ci-tests.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 95f7e2389..cc4ae4e93 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -13,24 +13,27 @@ jobs: name: Full Test Suite runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash -l {0} + strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python-version: [3.8] + python-version: [3.9] steps: - - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v3 - name: Install Linux dependencies if: runner.os == 'Linux' run: sudo apt-get install libopenblas-dev - name: Install macOS Dependencies - shell: bash -l {0} if: runner.os == 'macOS' - run: | - brew install libomp + run: brew install libomp - name: Set up conda uses: conda-incubator/setup-miniconda@v2 @@ -40,12 +43,9 @@ jobs: auto-activate-base: true - name: Install package - shell: bash -l {0} - run: | - ./install_shapepipe --develop + run: ./install_shapepipe --develop - name: Run tests - shell: bash -l {0} run: | conda activate shapepipe python setup.py test From 8ee2095059eb2c4646eaa9dbf485dc5e35ef4acf Mon Sep 17 00:00:00 2001 From: Fabian Hervas Date: Thu, 23 Feb 2023 14:37:33 +0100 Subject: [PATCH 16/41] new config files simu --- example/cfis_simu/.DS_Store | Bin 0 -> 6148 bytes example/cfis_simu/._.DS_Store | Bin 0 -> 4096 bytes example/cfis_simu/config.mask_simu | 86 ++++ example/cfis_simu/config_GitFeGie_symlink.ini | 146 ++++++ example/cfis_simu/config_MCCD.ini | 120 +++++ example/cfis_simu/config_MaMa.ini | 105 ++++ example/cfis_simu/config_exp_SpMh.ini | 84 ++++ example/cfis_simu/config_make_cat_mccd.ini | 77 +++ .../config_merge_sep_cats_template.ini | 75 +++ example/cfis_simu/config_tile.mask | 90 ++++ example/cfis_simu/config_tile.mask_simu | 90 ++++ example/cfis_simu/config_tile_MiViSmVi.ini | 181 +++++++ example/cfis_simu/config_tile_Ng_template.ini | 99 ++++ example/cfis_simu/config_tile_Sx_exp_mccd.ini | 285 +++++++++++ .../cfis_simu/config_tile_Sx_exp_psfex.ini | 248 ++++++++++ example/cfis_simu/default.conv | 5 + example/cfis_simu/default.param | 69 +++ example/cfis_simu/default.psfex | 85 ++++ example/cfis_simu/default_exp.sex | 133 +++++ example/cfis_simu/default_tile.sex | 133 +++++ example/cfis_simu/job_sp_simu.bash | 462 ++++++++++++++++++ .../mask_default/MEGAPRIME_star_i_13.8.reg | 24 + .../mask_default/Messier_catalog.npy | Bin 0 -> 4209 bytes .../mask_default/Messier_catalog_updated.fits | Bin 0 -> 8640 bytes example/cfis_simu/mask_default/default.ww | 40 ++ example/cfis_simu/mask_default/halo_mask.reg | 50 ++ example/cfis_simu/mask_default/ngc_cat.fits | Bin 0 -> 201600 bytes example/cfis_simu/readme.txt | 7 + example/cfis_simu/star_selection.setools | 104 ++++ example/cfis_simu/tile_numbers.txt | 1 + 30 files changed, 2799 insertions(+) create mode 100644 example/cfis_simu/.DS_Store create mode 100644 example/cfis_simu/._.DS_Store create mode 100644 example/cfis_simu/config.mask_simu create mode 100644 example/cfis_simu/config_GitFeGie_symlink.ini create mode 100644 example/cfis_simu/config_MCCD.ini create mode 100644 example/cfis_simu/config_MaMa.ini create mode 100644 example/cfis_simu/config_exp_SpMh.ini create mode 100644 example/cfis_simu/config_make_cat_mccd.ini create mode 100644 example/cfis_simu/config_merge_sep_cats_template.ini create mode 100644 example/cfis_simu/config_tile.mask create mode 100644 example/cfis_simu/config_tile.mask_simu create mode 100644 example/cfis_simu/config_tile_MiViSmVi.ini create mode 100644 example/cfis_simu/config_tile_Ng_template.ini create mode 100644 example/cfis_simu/config_tile_Sx_exp_mccd.ini create mode 100644 example/cfis_simu/config_tile_Sx_exp_psfex.ini create mode 100644 example/cfis_simu/default.conv create mode 100644 example/cfis_simu/default.param create mode 100644 example/cfis_simu/default.psfex create mode 100644 example/cfis_simu/default_exp.sex create mode 100644 example/cfis_simu/default_tile.sex create mode 100755 example/cfis_simu/job_sp_simu.bash create mode 100644 example/cfis_simu/mask_default/MEGAPRIME_star_i_13.8.reg create mode 100644 example/cfis_simu/mask_default/Messier_catalog.npy create mode 100644 example/cfis_simu/mask_default/Messier_catalog_updated.fits create mode 100644 example/cfis_simu/mask_default/default.ww create mode 100644 example/cfis_simu/mask_default/halo_mask.reg create mode 100644 example/cfis_simu/mask_default/ngc_cat.fits create mode 100644 example/cfis_simu/readme.txt create mode 100644 example/cfis_simu/star_selection.setools create mode 100644 example/cfis_simu/tile_numbers.txt diff --git a/example/cfis_simu/.DS_Store b/example/cfis_simu/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6b946e67e4da54b4cef0892f1b9d546e08938660 GIT binary patch literal 6148 zcmeHKOG*Pl5UtWE0T*T|WYag0++Y&M6XXIi8PLUq9*EiZNjy!qg5ZUG^@%cOz>SDV z6?DDs`t;|)bWafxulDVNXhuX+G(ncmh=_UAb>_hrK-M|-^wjP)U6XS+GSOc&$=)w1 z6LwC$=;QuzprNCCSgbdB+v_Q=pKrhVx4EvHE;q1)tulXkJ1kFQ+HYg}$Io@27-ZL;0GCyCk`^bG7KFI1Ovgq2Lp0HBs9Uwu^8&r0i`7Xa00Um`cg|sPI9aq ziy=G^wp5^{vX>Za>98k{s~n4=r4xJc!M^gbcwt=~^Ct}_t_(v51Hr(MfpZ(qw1Ml`P+JOJb7yq+C7?x#1-j4&>#E+U?BI%jXKSrq>s4D Wu^7rMV%KzF{0Jx^p@M;5VBj5;6*LI| literal 0 HcmV?d00001 diff --git a/example/cfis_simu/._.DS_Store b/example/cfis_simu/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7a2262ee0b2dff251292f5b68503b7de8fc90439 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIhYCu0iY;W;207T z#K0i552Ayi0;{4?!O;*H4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5TJ4hFapg3 zVK9&j$;d2LC`v8PFD*(=RY=P(%2vqCD@n~O$;{77%*m-#$Vp8rQAo;3%*zILb)mY3 QG==JaxL0Ht_vignet.fits +PREFIX = weight + + +[SPREAD_MODEL_RUNNER] + +INPUT_DIR = last:sextractor_runner_run_1, last:mccd_interp_runner, last:vignetmaker_runner_run_1 + +FILE_PATTERN = sexcat, galaxy_psf, weight_vignet + +FILE_EXT = .fits, .sqlite, .fits + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# Pixel scale in arcsec +PIXEL_SCALE = 0.186 + +# Output mode: +# new: create a new catalog with: [number, mag, sm, sm_err] +# add: create a copy of the input SExtractor with the column sm and sm_err +OUTPUT_MODE = new + + +[VIGNETMAKER_RUNNER_RUN_2] + +# Create multi-epoch vignets for tiles corresponding to +# positions on single-exposures + +INPUT_DIR = last:sextractor_runner_run_1 + +FILE_PATTERN = sexcat + +FILE_EXT = .fits + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +MASKING = False +MASK_VALUE = 0 + +# Run mode for psfex interpolation: +# CLASSIC: 'classical' run, interpolate to object positions +# MULTI-EPOCH: interpolate for multi-epoch images +# VALIDATION: validation for single-epoch images +MODE = MULTI-EPOCH + +# Coordinate frame type, one in PIX (pixel frame), SPHE (spherical coordinates) +COORD = SPHE +POSITION_PARAMS = XWIN_WORLD,YWIN_WORLD + +# Vignet size in pixels +STAMP_SIZE = 51 + +# Output file name prefix, file name is vignet.fits +PREFIX = + +# Additional parameters for path and file pattern corresponding to single-exposure +# run outputs +ME_IMAGE_DIR = split_exp_runner, split_exp_runner, split_exp_runner, sextractor_runner_run_2 +ME_IMAGE_PATTERN = flag, image, weight, background +ME_LOG_WCS = $SP_RUN/output/log_exp_headers.sqlite diff --git a/example/cfis_simu/config_tile_Ng_template.ini b/example/cfis_simu/config_tile_Ng_template.ini new file mode 100644 index 000000000..f97e8bc9d --- /dev/null +++ b/example/cfis_simu/config_tile_Ng_template.ini @@ -0,0 +1,99 @@ +# ShapePipe configuration file for tiles: ngmix + KSB + + +## Default ShapePipe options +[DEFAULT] + +# verbose mode (optional), default: True, print messages on terminal +VERBOSE = True + +# Name of run (optional) default: shapepipe_run +RUN_NAME = run_sp_tile_ngmix_NgXu + +# Add date and time to RUN_NAME, optional, default: False +RUN_DATETIME = False + + +## ShapePipe execution options +[EXECUTION] + +# Module name, single string or comma-separated list of valid module runner names +MODULE = ngmix_runner + +# Parallel processing mode, SMP or MPI +MODE = SMP + + +## ShapePipe file handling options +[FILE] + +# Log file master name, optional, default: shapepipe +LOG_NAME = log_sp + +# Runner log file name, optional, default: shapepipe_runs +RUN_LOG_NAME = log_run_sp + +# Input directory, containing input files, single string or list of names +INPUT_DIR = . + +# Output directory +OUTPUT_DIR = $SP_RUN/output + + +## ShapePipe job handling options +[JOB] + +# Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial +SMP_BATCH_SIZE = 16 + +# Timeout value (optional), default is None, i.e. no timeout limit applied +TIMEOUT = 96:00:00 + + +## Module options + +# Model-fitting shapes with ngmix +[NGMIX_RUNNER] + +INPUT_DIR = last:sextractor_runner_run_1,last:MCCD_interp_runner,last:vignetmaker_runner_run_2 + +FILE_PATTERN = sexcat, image_vignet, background_vignet, galaxy_psf, weight_vignet, flag_vignet + +FILE_EXT = .fits, .sqlite, .sqlite, .sqlite, .sqlite, .sqlite + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# Multi-epoch mode: Path to file with single-exposure WCS header information +LOG_WCS = $SP_RUN/output/log_exp_headers.sqlite + +# Magnitude zero-point +MAG_ZP = 30.0 + +# Pixel scale in arcsec +PIXEL_SCALE = 0.186 + +ID_OBJ_MIN = -1 +ID_OBJ_MAX = -1 + + +# Moment-based (KSB) shapes with galsim +[GALSIM_SHAPES_V2_RUNNER] + +INPUT_DIR = last:sextractor_runner_run_2, last:vignetmaker_runner_run_1, last:X_interp_runner,last:vignetmaker_runner_run_2 + +FILE_PATTERN = sexcat, weight_vignet, image_vignet, background_vignet, galaxy_psf, weight_vignet, flag_vignet + +FILE_EXT = .fits, .fits, .sqlite, .sqlite, .sqlite, .sqlite, .sqlite + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# Multi-epoch mode: Path to file with single-exposure WCS header information +LOG_WCS = $SP_RUN/output/log_exp_headers.sqlite + +# Magnitude zero-point +MAG_ZP = 30.0 + +ID_OBJ_MIN = -1 +ID_OBJ_MAX = -1 diff --git a/example/cfis_simu/config_tile_Sx_exp_mccd.ini b/example/cfis_simu/config_tile_Sx_exp_mccd.ini new file mode 100644 index 000000000..d78a72f5f --- /dev/null +++ b/example/cfis_simu/config_tile_Sx_exp_mccd.ini @@ -0,0 +1,285 @@ +# ShapePipe configuration file for single-exposures, MCCD PSF model. +# Process exposures after masking, from star detection to PSF model. + + +## Default ShapePipe options +[DEFAULT] + +# verbose mode (optional), default: True, print messages on terminal +VERBOSE = True + +# Name of run (optional) default: shapepipe_run +RUN_NAME = run_sp_tile_Sx_exp_SxSePsf + +# Add date and time to RUN_NAME, optional, default: True +; RUN_DATETIME = False + + +## ShapePipe execution options +[EXECUTION] + +# Module name, single string or comma-separated list of valid module runner names +MODULE = sextractor_runner, sextractor_runner, setools_runner, + mccd_preprocessing_runner, mccd_fit_val_runner, + merge_starcat_runner, mccd_plots_runner + +# Run mode, SMP or MPI +MODE = SMP + + +## ShapePipe file handling options +[FILE] + +# Log file master name, optional, default: shapepipe +LOG_NAME = log_sp + +# Runner log file name, optional, default: shapepipe_runs +RUN_LOG_NAME = log_run_sp + +# Input directory, containing input files, single string or list of names with length matching FILE_PATTERN +INPUT_DIR = . + +# Output directory +OUTPUT_DIR = $SP_RUN/output + + +## ShapePipe job handling options +[JOB] + +# Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial +SMP_BATCH_SIZE = 4 + +# Timeout value (optional), default is None, i.e. no timeout limit applied +TIMEOUT = 96:00:00 + + +## Module options + +## Detection on tile +[SEXTRACTOR_RUNNER_RUN_1] + +INPUT_DIR = last:get_images_runner_run_1, last:get_images_runner_run_1, last:mask_runner_run_1 + +FILE_PATTERN = CFIS_simu_image, CFIS_simu_weight, pipeline_flag + +FILE_EXT = .fits, .fits, .fits + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# SExtractor executable path +EXEC_PATH = sex + +# SExtractor configuration files +DOT_SEX_FILE = $SP_CONFIG/default_tile.sex +DOT_PARAM_FILE = $SP_CONFIG/default.param +DOT_CONV_FILE = $SP_CONFIG/default.conv + +# Use input weight image if True +WEIGHT_IMAGE = True + +# Use input flag image if True +FLAG_IMAGE = True + +# Use input PSF file if True +PSF_FILE = False + +# Use distinct image for detection (SExtractor in +# dual-image mode) if True +DETECTION_IMAGE = False + +# Distinct weight image for detection (SExtractor +# in dual-image mode) +DETECTION_WEIGHT = False + +ZP_FROM_HEADER = False + +BKG_FROM_HEADER = False + +# Type of image check (optional), default not used, can be a list of +# BACKGROUND, BACKGROUND_RMS, INIBACKGROUND, +# MINIBACK_RMS, -BACKGROUND, #FILTERED, +# OBJECTS, -OBJECTS, SEGMENTATION, APERTURES +#CHECKIMAGE = BACKGROUND + +# File name suffix for the output sextractor files (optional) +SUFFIX = sexcat + +## Post-processing + +# Necessary for tiles, to enable multi-exposure processing +MAKE_POST_PROCESS = True + +# Multi-epoch mode: Path to file with single-exposure WCS header information +LOG_WCS = $SP_RUN/output/log_exp_headers.sqlite + +# World coordinate keywords, SExtractor output. Format: KEY_X,KEY_Y +WORLD_POSITION = XWIN_WORLD,YWIN_WORLD + +# Number of pixels in x,y of a CCD. Format: Nx,Ny +CCD_SIZE = 33,2080,1,4612 + + +## Detection on single exposures +[SEXTRACTOR_RUNNER_RUN_2] + +INPUT_DIR = last:split_exp_runner, last:mask_runner_run_2 + +# Input from two modules +INPUT_MODULE = split_exp_runner, mask_runner_run_2 + +# Read pipeline flag files created by mask module +FILE_PATTERN = image, weight, flag + +NUMBERING_SCHEME = -0000000-0 + +# SExtractor executable path +EXEC_PATH = sex + +# SExtractor configuration files +DOT_SEX_FILE = $SP_CONFIG/default_exp.sex +DOT_PARAM_FILE = $SP_CONFIG//default.param +DOT_CONV_FILE = $SP_CONFIG/default.conv + +# Use input weight image if True +WEIGHT_IMAGE = True + +# Use input flag image if True +FLAG_IMAGE = True + +# Use input PSF file if True +PSF_FILE = False + +# Use distinct image for detection (SExtractor in +# dual-image mode) if True. +DETECTION_IMAGE = False + +# Distinct weight image for detection (SExtractor +# in dual-image mode) if True +DETECTION_WEIGHT = False + +# Se to True if photometry zero-point is to be read from exposure image header +ZP_FROM_HEADER = True + +# If ZP_FROM_HEADER is True, zero-point key name +ZP_KEY = PHOTZP + +# Background information from image header. +# If BKG_FROM_HEADER is True, background value will be read from header. +# In that case, the value of BACK_TYPE will be set atomatically to MANUAL. +# This is used e.g. for the LSB images. +BKG_FROM_HEADER = False +# LSB images: +# BKG_FROM_HEADER = True + +# If BKG_FROM_HEADER is True, background value key name +# LSB images: +#BKG_KEY = IMMODE + +# Type of image check (optional), default not used, can be a list of +# BACKGROUND, BACKGROUND_RMS, INIBACKGROUND, MINIBACK_RMS, -BACKGROUND, +# FILTERED, OBJECTS, -OBJECTS, SEGMENTATION, APERTURES +CHECKIMAGE = BACKGROUND + +# File name suffix for the output sextractor files (optional) SUFFIX = tile +SUFFIX = sexcat + +## Post-processing + +# Not required for single exposures +MAKE_POST_PROCESS = FALSE + + +[SETOOLS_RUNNER] + +INPUT_MODULE = sextractor_runner_run_2 + +# Note: Make sure this doe not match the SExtractor background images +# (sexcat_background*) +FILE_PATTERN = sexcat + +NUMBERING_SCHEME = -0000000-0 + +# SETools config file +SETOOLS_CONFIG_PATH = $SP_CONFIG/star_selection.setools + + +[MCCD_PREPROCESSING_RUNNER] + +# Path to MCCD config file +CONFIG_PATH = $SP_CONFIG/config_MCCD.ini + +MODE = FIT_VALIDATION + +VERBOSE = False + +INPUT_DIR = last:setools_runner + +# Input are individual CCDs, thus single-exposure single-HDU images +NUMBERING_SCHEME = -0000000-0 + +FILE_PATTERN = star_split_ratio_80, star_split_ratio_20 + +FILE_EXT = .fits, .fits + + +[MCCD_FIT_VAL_RUNNER] + +# Path to MCCD config file +CONFIG_PATH = $SP_CONFIG/config_MCCD.ini + +MODE = FIT_VALIDATION + +VERBOSE = False + +NUMBERING_SCHEME = -0000000 + + +[MERGE_STARCAT_RUNNER] + +INPUT_DIR = last:mccd_fit_val_runner + +# Path to MCCD config file +CONFIG_PATH = $SP_CONFIG/config_MCCD.ini + +MODE = FIT_VALIDATION + +VERBOSE = False + +PSF_MODEL = mccd + +NUMBERING_SCHEME = -0000000 + + +[MCCD_PLOTS_RUNNER] + +# Path to MCCD config file +CONFIG_PATH = $SP_CONFIG/config_MCCD.ini + +MODE = FIT_VALIDATION + +VERBOSE = False + +# Now MCCD has created a focal-plane PSF model, including all CCDS per images, +# thus single-exposure files +NUMBERING_SCHEME = -0000000 + +PSF = mccd + +PLOT_MEANSHAPES = True + +# X_GRID, Y_GRID: correspond to the number of bins in each direction of each +# CCD from the focal plane. Ex: each CCD will be binned in 5x10 regular grids. +X_GRID = 5 +Y_GRID = 10 + +PLOT_HISTOGRAMS = True + +# REMOVE_OUTLIERS: Remove validated stars that are outliers in terms of shape +# before drawing the plots. +REMOVE_OUTLIERS = False + +PLOT_RHO_STATS = False + +# RHO_STATS_STYLE: can be 'HSC' or 'DES' +RHO_STATS_STYLE = HSC diff --git a/example/cfis_simu/config_tile_Sx_exp_psfex.ini b/example/cfis_simu/config_tile_Sx_exp_psfex.ini new file mode 100644 index 000000000..1271eb012 --- /dev/null +++ b/example/cfis_simu/config_tile_Sx_exp_psfex.ini @@ -0,0 +1,248 @@ +# ShapePipe configuration file for single-exposures. PSFex PSF model. +# Process exposures after masking, from star detection to PSF model. + + +## Default ShapePipe options +[DEFAULT] + +# verbose mode (optional), default: True, print messages on terminal +VERBOSE = True + +# Name of run (optional) default: shapepipe_run +RUN_NAME = run_sp_tile_Sx_exp_SxSePsf + +# Add date and time to RUN_NAME, optional, default: True +; RUN_DATETIME = False + + +## ShapePipe execution options +[EXECUTION] + +# Module name, single string or comma-separated list of valid module runner names +MODULE = sextractor_runner, sextractor_runner, setools_runner, psfex_runner, psfex_interp_runner + + +# Run mode, SMP or MPI +MODE = SMP + + +## ShapePipe file handling options +[FILE] + +# Log file master name, optional, default: shapepipe +LOG_NAME = log_sp + +# Runner log file name, optional, default: shapepipe_runs +RUN_LOG_NAME = log_run_sp + +# Input directory, containing input files, single string or list of names with length matching FILE_PATTERN +INPUT_DIR = . + +# Output directory +OUTPUT_DIR = $SP_RUN/output + + +## ShapePipe job handling options +[JOB] + +# Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial +SMP_BATCH_SIZE = 40 + +# Timeout value (optional), default is None, i.e. no timeout limit applied +TIMEOUT = 96:00:00 + + +## Module options + +[SEXTRACTOR_RUNNER_RUN_1] + +INPUT_MODULE = get_images_runner_run_1, uncompress_fits_runner, mask_runner_run_1 + +INPUT_DIR = last:get_images_runner_run_1, last:uncompress_fits_runner, last:mask_runner_run_1 + +FILE_PATTERN = CFIS_image, CFIS_weight, pipeline_flag + +FILE_EXT = .fits, .fits, .fits + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# SExtractor executable path +EXEC_PATH = sex + +# SExtractor configuration files +DOT_SEX_FILE = $SP_CONFIG/default_tile.sex +DOT_PARAM_FILE = $SP_CONFIG/default.param +DOT_CONV_FILE = $SP_CONFIG/default.conv + +# Use input weight image if True +WEIGHT_IMAGE = True + +# Use input flag image if True +FLAG_IMAGE = True + +# Use input PSF file if True +PSF_FILE = False + +# Use distinct image for detection (SExtractor in +# dual-image mode) if True +DETECTION_IMAGE = False + +# Distinct weight image for detection (SExtractor +# in dual-image mode) +DETECTION_WEIGHT = False + +ZP_FROM_HEADER = False + +BKG_FROM_HEADER = False + +# Type of image check (optional), default not used, can be a list of +# BACKGROUND, BACKGROUND_RMS, INIBACKGROUND, +# MINIBACK_RMS, -BACKGROUND, #FILTERED, +# OBJECTS, -OBJECTS, SEGMENTATION, APERTURES +CHECKIMAGE = BACKGROUND + +# File name suffix for the output sextractor files (optional) +SUFFIX = sexcat + +## Post-processing + +# Necessary for tiles, to enable multi-exposure processing +MAKE_POST_PROCESS = True + +# Multi-epoch mode: Path to file with single-exposure WCS header information +LOG_WCS = $SP_RUN/output/log_exp_headers.sqlite + +# World coordinate keywords, SExtractor output. Format: KEY_X,KEY_Y +WORLD_POSITION = XWIN_WORLD,YWIN_WORLD + +# Number of pixels in x,y of a CCD. Format: Nx,Ny +CCD_SIZE = 33,2080,1,4612 + + +[SEXTRACTOR_RUNNER_RUN_2] + +# Somehow this works but not +# - omitting +# - $SP_RUN/output +#INPUT_DIR = . + +# Input from two modules +INPUT_MODULE = split_exp_runner, mask_runner + +# Read pipeline flag files created by mask module +FILE_PATTERN = image, weight, pipeline_flag + +NUMBERING_SCHEME = -0000000-0 + +# SExtractor executable path +EXEC_PATH = sex + +# SExtractor configuration files +DOT_SEX_FILE = $SP_CONFIG/default_exp.sex +DOT_PARAM_FILE = $SP_CONFIG//default.param +DOT_CONV_FILE = $SP_CONFIG/default.conv + +# Use input weight image if True +WEIGHT_IMAGE = True + +# Use input flag image if True +FLAG_IMAGE = True + +# Use input PSF file if True +PSF_FILE = False + +# Use distinct image for detection (SExtractor in +# dual-image mode) if True. +DETECTION_IMAGE = False + +# Distinct weight image for detection (SExtractor +# in dual-image mode) +DETECTION_WEIGHT = False + +# True if photometry zero-point is to be read from exposure image header +ZP_FROM_HEADER = True + +# If ZP_FROM_HEADER is True, zero-point key name +ZP_KEY = PHOTZP + +# Background information from image header. +# If BKG_FROM_HEADER is True, background value will be read from header. +# In that case, the value of BACK_TYPE will be set atomatically to MANUAL. +# This is used e.g. for the LSB images. +BKG_FROM_HEADER = False +# LSB images: +# BKG_FROM_HEADER = True + +# If BKG_FROM_HEADER is True, background value key name +# LSB images: +#BKG_KEY = IMMODE + +# Type of image check (optional), default not used, can be a list of +# BACKGROUND, BACKGROUND_RMS, INIBACKGROUND, MINIBACK_RMS, -BACKGROUND, +# FILTERED, OBJECTS, -OBJECTS, SEGMENTATION, APERTURES +CHECKIMAGE = BACKGROUND + +# File name suffix for the output sextractor files (optional) SUFFIX = tile +SUFFIX = sexcat + +## Post-processing + +# Not required for single exposures +MAKE_POST_PROCESS = FALSE + + +[SETOOLS_RUNNER] + +INPUT_MODULE = sextractor_runner_run_2 + +# Note: Make sure this doe not match the SExtractor background images +# (sexcat_background*) +FILE_PATTERN = sexcat + +NUMBERING_SCHEME = -0000000-0 + +# SETools config file +SETOOLS_CONFIG_PATH = $SP_CONFIG/star_selection.setools + + +[PSFEX_RUNNER] + +# Use 80% sample for PSF model +FILE_PATTERN = star_split_ratio_80 + +NUMBERING_SCHEME = -0000000-0 + +# Path to executable for the PSF model (optional) +EXEC_PATH = psfex + +# Default psfex configuration file +DOT_PSFEX_FILE = $SP_CONFIG/default.psfex + + +[PSFEX_INTERP_RUNNER] + +# Use 20% sample for PSF validation +FILE_PATTERN = star_split_ratio_80, star_split_ratio_20, psfex_cat + +FILE_EXT = .psf, .fits, .cat + +NUMBERING_SCHEME = -0000000-0 + +# Run mode for psfex interpolation: +# CLASSIC: 'classical' run, interpolate to object positions +# MULTI-EPOCH: interpolate for multi-epoch images +# VALIDATION: validation for single-epoch images +MODE = VALIDATION + +# Column names of position parameters +POSITION_PARAMS = XWIN_IMAGE,YWIN_IMAGE + +# If True, measure and store ellipticity of the PSF (using moments) +GET_SHAPES = True + +# Minimum number of stars per CCD for PSF model to be computed +STAR_THRESH = 22 + +# Maximum chi^2 for PSF model to be computed on CCD +CHI2_THRESH = 2 diff --git a/example/cfis_simu/default.conv b/example/cfis_simu/default.conv new file mode 100644 index 000000000..2590b9cba --- /dev/null +++ b/example/cfis_simu/default.conv @@ -0,0 +1,5 @@ +CONV NORM +# 3x3 ``all-ground'' convolution mask with FWHM = 2 pixels. +1 2 1 +2 4 2 +1 2 1 diff --git a/example/cfis_simu/default.param b/example/cfis_simu/default.param new file mode 100644 index 000000000..6521a94d5 --- /dev/null +++ b/example/cfis_simu/default.param @@ -0,0 +1,69 @@ +NUMBER #Running object number +EXT_NUMBER #FITS extension number + +FLUX_AUTO #Flux within a Kron-like elliptical aperture [count] +FLUXERR_AUTO #RMS error for AUTO flux [count] +MAG_AUTO #Kron-like elliptical aperture magnitude [mag] +MAGERR_AUTO #RMS error for AUTO magnitude [mag] +FLUX_WIN #Gaussian-weighted flux [count] +FLUXERR_WIN #RMS error for WIN flux [count] +MAG_WIN #Gaussian-weighted magnitude [mag] +MAGERR_WIN #RMS error for MAG_WIN [mag] +FLUX_APER(1) +FLUXERR_APER(1) + +FLUX_RADIUS #Fraction-of-light radii [pixel] + +SNR_WIN #Gaussian-weighted SNR + +BACKGROUND #Background at centroid position [count] +THRESHOLD #Detection threshold above background [count] + +X_IMAGE #Object position along x [pixel] +Y_IMAGE #Object position along y [pixel] + +X_WORLD #Barycenter position along world x axis [deg] +Y_WORLD #Barycenter position along world y axis [deg] + +X2_IMAGE #Variance along x [pixel**2] +Y2_IMAGE #Variance along y [pixel**2] +XY_IMAGE #Covariance between x and y [pixel**2] +ERRX2_IMAGE #Variance of position along x [pixel**2] +ERRY2_IMAGE #Variance of position along y [pixel**2] +ERRXY_IMAGE #Covariance of position between x and y [pixel**2] + +XWIN_IMAGE #Windowed position estimate along x [pixel] +YWIN_IMAGE #Windowed position estimate along y [pixel] + +XWIN_WORLD #Windowed position along world x axis [deg] +YWIN_WORLD #Windowed position along world y axis [deg] + +X2WIN_IMAGE #Windowed variance along x [pixel**2] +Y2WIN_IMAGE #Windowed variance along y [pixel**2] +XYWIN_IMAGE #Windowed covariance between x and y [pixel**2] +ERRX2WIN_IMAGE #Variance of windowed pos along x [pixel**2] +ERRY2WIN_IMAGE #Variance of windowed pos along y [pixel**2] +ERRXYWIN_IMAGE #Covariance of windowed pos between x and y [pixel**2] + +MU_THRESHOLD #Analysis threshold above background [mag * arcsec**(-2)] +MU_MAX #Peak surface brightness above background [mag * arcsec**(-2)] + +FLAGS #Extraction flags +FLAGS_WIN #Flags for WINdowed parameters + +#!!! REQUIRE FLAG_IMAGE !!! +IMAFLAGS_ISO #FLAG-image flags OR'ed over the iso. profile !!! REQUIRE FLAG_IMAGE !!! + +FWHM_IMAGE #FWHM assuming a gaussian core [pixel] +FWHM_WORLD #FWHM assuming a gaussian core [deg] +ELONGATION #A_IMAGE/B_IMAGE +ELLIPTICITY #1 - B_IMAGE/A_IMAGE + +VIGNET(51,51) #Pixel data around detection [count] + +#VECTOR_ASSOC #ASSOCiated parameter vector +#NUMBER_ASSOC #Number of ASSOCiated IDs + +#SPREAD_MODEL +#SPREADERR_MODEL +#FWHMPSF_IMAGE diff --git a/example/cfis_simu/default.psfex b/example/cfis_simu/default.psfex new file mode 100644 index 000000000..15af2dc29 --- /dev/null +++ b/example/cfis_simu/default.psfex @@ -0,0 +1,85 @@ +# Default configuration file for PSFEx 3.17.1 +# EB 2017-11-30 +# + +#-------------------------------- PSF model ---------------------------------- + +BASIS_TYPE PIXEL # NONE, PIXEL, GAUSS-LAGUERRE or FILE +BASIS_NUMBER 20 # Basis number or parameter +BASIS_NAME basis.fits # Basis filename (FITS data-cube) +BASIS_SCALE 1.0 # Gauss-Laguerre beta parameter +NEWBASIS_TYPE NONE # Create new basis: NONE, PCA_INDEPENDENT + # or PCA_COMMON +NEWBASIS_NUMBER 8 # Number of new basis vectors +PSF_SAMPLING 1. # Sampling step in pixel units (0.0 = auto) +PSF_PIXELSIZE 1.0 # Effective pixel size in pixel step units +PSF_ACCURACY 0.01 # Accuracy to expect from PSF "pixel" values +PSF_SIZE 51,51 # Image size of the PSF model +PSF_RECENTER N # Allow recentering of PSF-candidates Y/N ? +MEF_TYPE INDEPENDENT # INDEPENDENT or COMMON + +#------------------------- Point source measurements ------------------------- + +CENTER_KEYS XWIN_IMAGE,YWIN_IMAGE # Catalogue parameters for source pre-centering +PHOTFLUX_KEY FLUX_AUTO # Catalogue parameter for photometric norm. +PHOTFLUXERR_KEY FLUXERR_AUTO # Catalogue parameter for photometric error + +#----------------------------- PSF variability ------------------------------- + +PSFVAR_KEYS XWIN_IMAGE,YWIN_IMAGE # Catalogue or FITS (preceded by :) params +PSFVAR_GROUPS 1,1 # Group tag for each context key +PSFVAR_DEGREES 2 # Polynom degree for each group +PSFVAR_NSNAP 9 # Number of PSF snapshots per axis +HIDDENMEF_TYPE COMMON # INDEPENDENT or COMMON +STABILITY_TYPE EXPOSURE # EXPOSURE or SEQUENCE + +#----------------------------- Sample selection ------------------------------ + +SAMPLE_AUTOSELECT N # Automatically select the FWHM (Y/N) ? + +BADPIXEL_FILTER N # Filter bad-pixels in samples (Y/N) ? +BADPIXEL_NMAX 0 # Maximum number of bad pixels allowed + +#----------------------- PSF homogeneisation kernel -------------------------- + +HOMOBASIS_TYPE NONE # NONE or GAUSS-LAGUERRE +HOMOBASIS_NUMBER 10 # Kernel basis number or parameter +HOMOBASIS_SCALE 1.0 # GAUSS-LAGUERRE beta parameter +HOMOPSF_PARAMS 2.0, 3.0 # Moffat parameters of the idealised PSF +HOMOKERNEL_DIR # Where to write kernels (empty=same as input) +HOMOKERNEL_SUFFIX .homo.fits # Filename extension for homogenisation kernels + +#----------------------------- Output catalogs ------------------------------- + +OUTCAT_TYPE FITS_LDAC # NONE, ASCII_HEAD, ASCII, FITS_LDAC + +#------------------------------- Check-plots ---------------------------------- + +CHECKPLOT_DEV PNG # NULL, XWIN, TK, PS, PSC, XFIG, PNG, + # JPEG, AQT, PDF or SVG +CHECKPLOT_RES 0 # Check-plot resolution (0 = default) +CHECKPLOT_ANTIALIAS Y # Anti-aliasing using convert (Y/N) ? +CHECKPLOT_TYPE NONE # FWHM,ELLIPTICITY,COUNTS, COUNT_FRACTION, CHI2, RESIDUALS +CHECKPLOT_TYPE FWHM,ELLIPTICITY,COUNTS, COUNT_FRACTION, CHI2, RESIDUALS + # or NONE +CHECKPLOT_NAME fwhm, ellipticity, counts, countfrac, chi2, resi + +#------------------------------ Check-Images --------------------------------- + +# Note: Check-image types can be set the ShapePipe config file, psfex_runner section +####### +#CHECKIMAGE_TYPE NONE # CHI,PROTOTYPES,SAMPLES,RESIDUALS,SNAPSHOTS + # or MOFFAT,-MOFFAT,-SYMMETRICAL +#CHECKIMAGE_NAME chi.fits,proto.fits,samp.fits,resi.fits,snap.fits + # Check-image filenames +#CHECKIMAGE_CUBE N # Save check-images as datacubes (Y/N) ? + +#----------------------------- Miscellaneous --------------------------------- + +PSF_SUFFIX .psf # Filename extension for output PSF filename +VERBOSE_TYPE NORMAL # can be QUIET,NORMAL,LOG or FULL +WRITE_XML N # Write XML file (Y/N)? + +NTHREADS 1 # Number of simultaneous threads for + # the SMP version of PSFEx + # 0 = automatic diff --git a/example/cfis_simu/default_exp.sex b/example/cfis_simu/default_exp.sex new file mode 100644 index 000000000..b87275ecb --- /dev/null +++ b/example/cfis_simu/default_exp.sex @@ -0,0 +1,133 @@ +# Default configuration file for SExtractor 2.19.5 +# EB 2017-11-30 +# + +#-------------------------------- Catalog ------------------------------------ + +CATALOG_TYPE FITS_LDAC + +PARAMETERS_NAME default.param + +#------------------------------- Extraction ---------------------------------- + +DETECT_TYPE CCD # CCD (linear) or PHOTO (with gamma correction) +DETECT_MINAREA 5 # min. # of pixels above threshold +DETECT_MAXAREA 0 # max. # of pixels above threshold (0=unlimited) +THRESH_TYPE RELATIVE # threshold type: RELATIVE (in sigmas) + # or ABSOLUTE (in ADUs) +DETECT_THRESH 1.5 # or , in mag.arcsec-2 +ANALYSIS_THRESH 1.5 # or , in mag.arcsec-2 + +FILTER Y # apply filter for detection (Y or N)? +FILTER_NAME default.conv +FILTER_THRESH # Threshold[s] for retina filtering + +DEBLEND_NTHRESH 32 # Number of deblending sub-thresholds +DEBLEND_MINCONT 0.001 # Minimum contrast parameter for deblending + +CLEAN Y # Clean spurious detections? (Y or N)? +CLEAN_PARAM 1.0 # Cleaning efficiency + +MASK_TYPE CORRECT # type of detection MASKing: can be one of + # NONE, BLANK or CORRECT + +#-------------------------------- WEIGHTing ---------------------------------- + +WEIGHT_TYPE MAP_WEIGHT # type of WEIGHTing: NONE, BACKGROUND, + # MAP_RMS, MAP_VAR or MAP_WEIGHT +RESCALE_WEIGHTS Y # Rescale input weights/variances (Y/N)? +WEIGHT_IMAGE weight.fits # weight-map filename +WEIGHT_GAIN Y # modulate gain (E/ADU) with weights? (Y/N) +WEIGHT_THRESH # weight threshold[s] for bad pixels + +#-------------------------------- FLAGging ----------------------------------- + +FLAG_IMAGE flag.fits # filename for an input FLAG-image +FLAG_TYPE OR # flag pixel combination: OR, AND, MIN, MAX + # or MOST + +#------------------------------ Photometry ----------------------------------- + +PHOT_APERTURES 5 # MAG_APER aperture diameter(s) in pixels +PHOT_AUTOPARAMS 2.5, 3.5 # MAG_AUTO parameters: , +PHOT_PETROPARAMS 2.0, 3.5 # MAG_PETRO parameters: , + # +PHOT_AUTOAPERS 0.0,0.0 # , minimum apertures + # for MAG_AUTO and MAG_PETRO +PHOT_FLUXFRAC 0.5 # flux fraction[s] used for FLUX_RADIUS + +SATUR_KEY SATURATE # keyword for saturation level (in ADUs) + +MAG_ZEROPOINT 30.0 # magnitude zero-point +MAG_GAMMA 4.0 # gamma of emulsion (for photographic scans) + +GAIN_KEY GAIN # keyword for detector gain in e-/ADU +PIXEL_SCALE 0. # size of pixel in arcsec (0=use FITS WCS info) + +#------------------------- Star/Galaxy Separation ---------------------------- + +SEEING_FWHM 0.6 # stellar FWHM in arcsec +STARNNW_NAME default.nnw + +#------------------------------ Background ----------------------------------- + +BACK_TYPE AUTO # AUTO or MANUAL +BACK_VALUE 0.0 # Default background value in MANUAL mode +BACK_SIZE 64 # Background mesh: or , +BACK_FILTERSIZE 3 # Background filter: or , + +BACKPHOTO_TYPE GLOBAL # can be GLOBAL or LOCAL +BACKPHOTO_THICK 24 # thickness of the background LOCAL annulus +BACK_FILTTHRESH 0.0 # Threshold above which the background- + # map filter operates + +#------------------------------ Check Image ---------------------------------- + +####### +## AG : This parameter is set in pipeline config file. +####### +# CHECKIMAGE_TYPE NONE #BACKGROUND_RMS,BACKGROUND +# can be NONE, BACKGROUND, BACKGROUND_RMS, + # MINIBACKGROUND, MINIBACK_RMS, -BACKGROUND, + # FILTERED, OBJECTS, -OBJECTS, SEGMENTATION, + # or APERTURES +# CHECKIMAGE_NAME check.fits,back.fits +# Filename for the check-image + +#--------------------- Memory (change with caution!) ------------------------- + +MEMORY_OBJSTACK 3000 # number of objects in stack +MEMORY_PIXSTACK 300000 # number of pixels in stack +MEMORY_BUFSIZE 1024 # number of lines in buffer + +#------------------------------- ASSOCiation --------------------------------- + +ASSOC_NAME sky.list # name of the ASCII file to ASSOCiate +ASSOC_DATA 2,3,4 # columns of the data to replicate (0=all) +ASSOC_PARAMS 2,3,4 # columns of xpos,ypos[,mag] +ASSOCCOORD_TYPE PIXEL # ASSOC coordinates: PIXEL or WORLD +ASSOC_RADIUS 2.0 # cross-matching radius (pixels) +ASSOC_TYPE NEAREST # ASSOCiation method: FIRST, NEAREST, MEAN, + # MAG_MEAN, SUM, MAG_SUM, MIN or MAX +ASSOCSELEC_TYPE MATCHED # ASSOC selection type: ALL, MATCHED or -MATCHED + +#----------------------------- Miscellaneous --------------------------------- + +VERBOSE_TYPE NORMAL # can be QUIET, NORMAL or FULL +HEADER_SUFFIX .head # Filename extension for additional headers +WRITE_XML N # Write XML file (Y/N)? + +NTHREADS 1 # 1 single thread + +FITS_UNSIGNED N # Treat FITS integer values as unsigned (Y/N)? +INTERP_MAXXLAG 16 # Max. lag along X for 0-weight interpolation +INTERP_MAXYLAG 16 # Max. lag along Y for 0-weight interpolation +INTERP_TYPE ALL # Interpolation type: NONE, VAR_ONLY or ALL + +#--------------------------- Experimental Stuff ----------------------------- + +#PSF_NAME default.psf # File containing the PSF model +#PSF_NMAX 1 # Max.number of PSFs fitted simultaneously +#PATTERN_TYPE RINGS-HARMONIC # can RINGS-QUADPOLE, RINGS-OCTOPOLE, + # RINGS-HARMONICS or GAUSS-LAGUERRE +#SOM_NAME default.som # File containing Self-Organizing Map weights diff --git a/example/cfis_simu/default_tile.sex b/example/cfis_simu/default_tile.sex new file mode 100644 index 000000000..ff3b25213 --- /dev/null +++ b/example/cfis_simu/default_tile.sex @@ -0,0 +1,133 @@ +# Default configuration file for SExtractor 2.19.5 +# EB 2017-11-30 +# + +#-------------------------------- Catalog ------------------------------------ + +CATALOG_TYPE FITS_LDAC + +PARAMETERS_NAME default.param + +#------------------------------- Extraction ---------------------------------- + +DETECT_TYPE CCD # CCD (linear) or PHOTO (with gamma correction) +DETECT_MINAREA 5 # min. # of pixels above threshold +DETECT_MAXAREA 0 # max. # of pixels above threshold (0=unlimited) +THRESH_TYPE RELATIVE # threshold type: RELATIVE (in sigmas) + # or ABSOLUTE (in ADUs) +DETECT_THRESH 1.5 # or , in mag.arcsec-2 +ANALYSIS_THRESH 1.5 # or , in mag.arcsec-2 + +FILTER Y # apply filter for detection (Y or N)? +FILTER_NAME default.conv +FILTER_THRESH # Threshold[s] for retina filtering + +DEBLEND_NTHRESH 32 # Number of deblending sub-thresholds +DEBLEND_MINCONT 0.0005 # Minimum contrast parameter for deblending + +CLEAN Y # Clean spurious detections? (Y or N)? +CLEAN_PARAM 1.0 # Cleaning efficiency + +MASK_TYPE CORRECT # type of detection MASKing: can be one of + # NONE, BLANK or CORRECT + +#-------------------------------- WEIGHTing ---------------------------------- + +WEIGHT_TYPE MAP_WEIGHT # type of WEIGHTing: NONE, BACKGROUND, + # MAP_RMS, MAP_VAR or MAP_WEIGHT +RESCALE_WEIGHTS Y # Rescale input weights/variances (Y/N)? +WEIGHT_IMAGE weight.fits # weight-map filename +WEIGHT_GAIN Y # modulate gain (E/ADU) with weights? (Y/N) +WEIGHT_THRESH # weight threshold[s] for bad pixels + +#-------------------------------- FLAGging ----------------------------------- + +FLAG_IMAGE flag.fits # filename for an input FLAG-image +FLAG_TYPE OR # flag pixel combination: OR, AND, MIN, MAX + # or MOST + +#------------------------------ Photometry ----------------------------------- + +PHOT_APERTURES 5 # MAG_APER aperture diameter(s) in pixels +PHOT_AUTOPARAMS 2.5, 3.5 # MAG_AUTO parameters: , +PHOT_PETROPARAMS 2.0, 3.5 # MAG_PETRO parameters: , + # +PHOT_AUTOAPERS 0.0,0.0 # , minimum apertures + # for MAG_AUTO and MAG_PETRO +PHOT_FLUXFRAC 0.5 # flux fraction[s] used for FLUX_RADIUS + +SATUR_KEY SATURATE # keyword for saturation level (in ADUs) + +MAG_ZEROPOINT 30.0 # magnitude zero-point +MAG_GAMMA 4.0 # gamma of emulsion (for photographic scans) + +GAIN_KEY GAIN # keyword for detector gain in e-/ADU +PIXEL_SCALE 0. # size of pixel in arcsec (0=use FITS WCS info) + +#------------------------- Star/Galaxy Separation ---------------------------- + +SEEING_FWHM 0.6 # stellar FWHM in arcsec +STARNNW_NAME default.nnw + +#------------------------------ Background ----------------------------------- + +BACK_TYPE MANUAL # AUTO or MANUAL +BACK_VALUE 0.0 # Default background value in MANUAL mode +BACK_SIZE 64 # Background mesh: or , +BACK_FILTERSIZE 3 # Background filter: or , + +BACKPHOTO_TYPE GLOBAL # can be GLOBAL or LOCAL +BACKPHOTO_THICK 24 # thickness of the background LOCAL annulus +BACK_FILTTHRESH 0.0 # Threshold above which the background- + # map filter operates + +#------------------------------ Check Image ---------------------------------- + +####### +## AG : This parameter is set in pipeline config file. +####### +# CHECKIMAGE_TYPE NONE #BACKGROUND_RMS,BACKGROUND +# can be NONE, BACKGROUND, BACKGROUND_RMS, + # MINIBACKGROUND, MINIBACK_RMS, -BACKGROUND, + # FILTERED, OBJECTS, -OBJECTS, SEGMENTATION, + # or APERTURES +# CHECKIMAGE_NAME check.fits,back.fits +# Filename for the check-image + +#--------------------- Memory (change with caution!) ------------------------- + +MEMORY_OBJSTACK 3000 # number of objects in stack +MEMORY_PIXSTACK 300000 # number of pixels in stack +MEMORY_BUFSIZE 1024 # number of lines in buffer + +#------------------------------- ASSOCiation --------------------------------- + +ASSOC_NAME sky.list # name of the ASCII file to ASSOCiate +ASSOC_DATA 2,3,4 # columns of the data to replicate (0=all) +ASSOC_PARAMS 2,3,4 # columns of xpos,ypos[,mag] +ASSOCCOORD_TYPE PIXEL # ASSOC coordinates: PIXEL or WORLD +ASSOC_RADIUS 2.0 # cross-matching radius (pixels) +ASSOC_TYPE NEAREST # ASSOCiation method: FIRST, NEAREST, MEAN, + # MAG_MEAN, SUM, MAG_SUM, MIN or MAX +ASSOCSELEC_TYPE MATCHED # ASSOC selection type: ALL, MATCHED or -MATCHED + +#----------------------------- Miscellaneous --------------------------------- + +VERBOSE_TYPE NORMAL # can be QUIET, NORMAL or FULL +HEADER_SUFFIX .head # Filename extension for additional headers +WRITE_XML N # Write XML file (Y/N)? + +NTHREADS 1 # 1 single thread + +FITS_UNSIGNED N # Treat FITS integer values as unsigned (Y/N)? +INTERP_MAXXLAG 16 # Max. lag along X for 0-weight interpolation +INTERP_MAXYLAG 16 # Max. lag along Y for 0-weight interpolation +INTERP_TYPE ALL # Interpolation type: NONE, VAR_ONLY or ALL + +#--------------------------- Experimental Stuff ----------------------------- + +#PSF_NAME default.psf # File containing the PSF model +#PSF_NMAX 1 # Max.number of PSFs fitted simultaneously +#PATTERN_TYPE RINGS-HARMONIC # can RINGS-QUADPOLE, RINGS-OCTOPOLE, + # RINGS-HARMONICS or GAUSS-LAGUERRE +#SOM_NAME default.som # File containing Self-Organizing Map weights diff --git a/example/cfis_simu/job_sp_simu.bash b/example/cfis_simu/job_sp_simu.bash new file mode 100755 index 000000000..09915cae3 --- /dev/null +++ b/example/cfis_simu/job_sp_simu.bash @@ -0,0 +1,462 @@ +#!/usr/bin/env bash + +# Name: job_sp_simu.bash +# Description: General script to process one or more tiles +# with all contributing exposures. +# This works as job submission script. +# called in interactive mode on a virtual +# machine. +# Author: Martin Kilbinger +# Date: v1.0 11/2020 +# v1.1 01/2021 + + +# VM home, required for canfar run. +## On other machines set to $HOME +export VM_HOME=/home/ubuntu +if [ ! -d "$VM_HOME" ]; then + export VM_HOME=$HOME +fi + +# Command line arguments +## Default values +job=255 +#config_dir='vos:cfis/cosmostat/kilbinger/cfis' +config_dir="$VM_HOME/SP_simu" +psf='mccd' +#retrieve='vos' +retrieve=symlink +results="$VM_HOME/SP_simu" +nsh_step=3200 +nsh_max=-1 +nsh_jobs=8 + +## Help string +usage="Usage: $(basename "$0") [OPTIONS] TILE_ID_1 [TILE_ID_2 [...]] +\n\nOptions:\n + -h\tthis message\n + -j, --job JOB\tRunning JOB, bit-coded\n + \t 1: retrieve images (online if method=vos)\n + \t 2: prepare images (offline)\n + \t 4: mask (online)\n + \t 8: detection of galaxies on tiles; processing of stars on exposures (offline)\n + \t 16: galaxy selection on tiles (offline)\n + \t 32: shapes and morphology (offline)\n + \t 64: paste catalogues (offline)\n + \t 128: upload results (online)\n + -c, --config_dir DIR\n + \t config file directory, default='$config_dir'\n + -p, --psf MODEL\n + \tPSF model, one in ['psfex'|'mccd'], default='$psf'\n + -r, --retrieve METHOD\n + \tmethod to retrieve images, one in ['vos'|'symlink]', default='$retrieve'\n + -o, --output_dir\n + \toutput (upload) directory on vos:cfis, default='$results'\n + --nsh_jobs NJOB\n + \tnumber of shape measurement parallel jobs, default=$nsh_jobs\n + --nsh_step NSTEP\n + \tnumber of objects per parallel shape module call, \n + \t default: $nsh_step\n + --nsh_max NMAX\n + \tmax number of objects per parallel shape module call, \n + \t default: unlimited; has precedent over --nsh_step\n + TILE_ID_i\n + \ttile ID(s), e.g. 283.247 214.242\n +" + +## Help if no arguments +if [ -z $1 ]; then + echo -ne $usage + exit 1 +fi + +## Parse command line +TILE_ARR=() +while [ $# -gt 0 ]; do + case "$1" in + -h) + echo -ne $usage + exit 0 + ;; + -j|--job) + job="$2" + shift + ;; + -c|--config_dir) + config_dir="$2" + shift + ;; + -p|--psf) + psf="$2" + shift + ;; + -r|--retrieve) + retrieve="$2" + shift + ;; + -o|--output_dir) + results="$2" + shift + ;; + --nsh_max) + nsh_max="$2" + shift + ;; + --nsh_step) + nsh_step="$2" + shift + ;; + --nsh_jobs) + nsh_jobs="$2" + shift + ;; + *) + TILE_ARR+=("$1") + ;; + esac + shift +done + +## Check options +if [ "$psf" != "psfex" ] && [ "$psf" != "mccd" ]; then + echo "PSF (option -p) needs to be 'psfex' or 'mccd'" + exit 2 +fi +n_tile=${#TILE_ARR[@]} +if [ "$n_tile" == "0" ]; then + echo "No tile ID given" + exit 3 +fi +if [ $nsh_max != -1 ]; then + nsh_step=$nsh_max +fi + +# For tar archives. Should be unique to each job +export ID=`echo ${TILE_ARR[@]} | tr ' ' '_'` + +## Paths + +# SExtractor library bug work-around +export PATH="$PATH:$VM_HOME/bin" + +## Path variables used in shapepipe config files + +# Run path and location of input image directories +export SP_RUN=`pwd` + +# Config file path +export SP_CONFIG=$SP_RUN +export SP_CONFIG_MOD=$SP_RUN + + +## Other variables + +# Input tile numbers ASCII file +export TILE_NUMBERS_PATH=tile_numbers.txt + +# Output +OUTPUT=$SP_RUN/output + +# For tar archives +output_rel=`realpath --relative-to=. $OUTPUT` + +# Stop on error, default=1 +STOP=1 + +# Verbose mode (1: verbose, 0: quiet) +VERBOSE=1 + +# VCP options +export CERTFILE=$VM_HOME/.ssl/cadcproxy.pem +export VCP="vcp --certfile=$CERTFILE" + + +## Functions + +# Print string, executes command, and prints return value. +function command () { + cmd=$1 + str=$2 + + #RED='\033[0;31m' + #GREEN='\033[0;32m' + #NC='\033[0m' # No Color + # Color escape characters show up in log files + RED='' + GREEN='' + NC='' + + + if [ $# == 2 ]; then + if [ $VERBOSE == 1 ]; then + echo "$str: running '$cmd'" + fi + $cmd + else + if [ $VERBOSE == 1 ]; then + echo "$str: running '$cmd $4 \"$5 $6\"'" + fi + $cmd $4 "$5 $6" + fi + res=$? + + if [ $VERBOSE == 1 ]; then + if [ $res == 0 ]; then + echo -e "${GREEN}success, return value = $res${NC}" + else + echo -e "${RED}error, return value = $res${NC}" + if [ $STOP == 1 ]; then + echo "${RED}exiting 'canfar_sp.bash', error in command '$cmd'${NC}" + exit $res + else + echo "${RED}continuing 'canfar_sp.bash', error in command '$cmd'${NC}" + fi + fi + fi + + #return $res +} + +# Run shapepipe command. If error occurs, upload sp log files before stopping script. +command_sp() { + cmd=$1 + str=$2 + + command "$1" "$2" +} + +# Tar and upload files to vos +function upload() { + base=$1 + shift + ID=$1 + shift + verbose=$1 + shift + upl=("$@") + + echo "Counting upload files" + n_upl=(`ls -l ${upl[@]} | wc`) + if [ $n_upl == 0 ]; then + if [ $STOP == 1 ]; then + echo "Exiting script, no file found for '$base' tar ball" + exit 3 + fi + fi + tar czf ${base}_${ID}.tgz ${upl[@]} + command "$VCP ${base}_${ID}.tgz vos:cfis/$results" "Upload tar ball" +} + +# Upload log files +function upload_logs() { + id=$1 + verbose=$2 + + upl="$output_rel/*/*/logs $output_rel/*/logs" + upload "logs" "$id" "$verbose" "${upl[@]}" +} + +# Print script variables +function print_env() { + echo "*** Environment ***" + echo "Data:" + echo " TILE_ARR=${TILE_ARR[@]}" + echo "Paths:" + echo " VM_HOME=$VM_HOME" + echo " SP_RUN=$SP_RUN" + echo " TILE_NUMBERS_PATH=$TILE_NUMBERS_PATH" + echo " OUTPUT=$OUTPUT" + echo " SP_CONFIG=$SP_CONFIG" + echo "Other variables:" + echo " VCP=$VCP" + echo " CERTFILE=$CERTFILE" + echo "***" +} + + +### Start ### + +echo "Start" + +echo "Processing $n_tile tile(s)" + +# Create input and output directories +mkdir -p $SP_RUN +cd $SP_RUN +mkdir -p $OUTPUT + +# Processing + +## Retrieve config files and images (online if retrieve=vos) +(( do_job= $job & 1 )) +if [[ $do_job != 0 ]]; then + + # Write tile numbers to ASCII input file + rm -rf $TILE_NUMBERS_PATH + for TILE in ${TILE_ARR[@]}; do + echo $TILE >> $TILE_NUMBERS_PATH + done + + ### Retrieve config files + if [[ $config_dir == *"vos:"* ]]; then + command_sp "$VCP $config_dir ." "Retrieve shapepipe config files" + else + if [[ ! -L cfis ]]; then + command_sp "ln -s $config_dir cfis" "Retrieve shapepipe config files" + fi + fi + + ### Retrieve files + command_sp "shapepipe_run -c $SP_CONFIG/config_GitFeGie_$retrieve.ini" "Retrieve images" + +fi + +## Prepare images (offline) +(( do_job= $job & 2 )) +if [[ $do_job != 0 ]]; then + + ### Uncompress tile weights + #command_sp "shapepipe_run -c $SP_CONFIG/config_tile_Uz.ini" "Run shapepipe (uncompress tile weights)" + + ### Split images into single-HDU files, merge headers for WCS info + command_sp "shapepipe_run -c $SP_CONFIG/config_exp_SpMh.ini" "Run shapepipe (split images, merge headers)" + +fi + +## Mask tiles and exposures: add star, halo, and Messier object masks (online) +(( do_job= $job & 4 )) +if [[ $do_job != 0 ]]; then + + ### Mask tiles and exposures + command_sp "shapepipe_run -c $SP_CONFIG/config_MaMa.ini" "Run shapepipe (mask)" + +fi + + +## Remaining exposure processing (offline) +(( do_job= $job & 8 )) +if [[ $do_job != 0 ]]; then + + ### Star detection, selection, PSF model. setools can exit with an error for CCD with insufficient stars, + ### the script should continue + STOP=0 + command_sp "shapepipe_run -c $SP_CONFIG/config_tile_Sx_exp_${psf}.ini" "Run shapepipe (tile detection, exp $psf)" + STOP=1 + +fi + +## Process tiles up to shape measurement +(( do_job= $job & 16 )) +if [[ $do_job != 0 ]]; then + + ### PSF model letter: 'P' (psfex) or 'M' (mccd) + letter=${psf:0:1} + Letter=${letter^} + command_sp "shapepipe_run -c $SP_CONFIG/config_tile_${Letter}iViSmVi.ini" "Run shapepipe (tile PsfInterp=$Letter}: up to ngmix+galsim)" + +fi + +## Shape measurement (offline) +(( do_job= $job & 32 )) +if [[ $do_job != 0 ]]; then + + ### Prepare config files + mkdir -p $SP_CONFIG_MOD + n_min=0 + n_max=$((nsh_step - 1)) + for k in $(seq 1 $nsh_jobs); do + cat $SP_CONFIG/config_tile_Ng_template.ini | \ + perl -ane \ + 's/(ID_OBJ_MIN =) X/$1 '$n_min'/; s/(ID_OBJ_MAX =) X/$1 '$n_max'/; s/NgXu/Ng'$k'u/; s/X_interp/'$psf'_interp/g; print' \ + > $SP_CONFIG_MOD/config_tile_Ng${k}u.ini + n_min=$((n_min + nsh_step)) + if [ "$k" == $((nsh_jobs - 1)) ] && [ $nsh_max == -1 ]; then + n_max=-1 + else + n_max=$((n_min + nsh_step - 1)) + fi + done + + ### Shapes, run $nsh_jobs parallel processes + VERBOSE=0 + for k in $(seq 1 $nsh_jobs); do + command_sp "shapepipe_run -c $SP_CONFIG_MOD/config_tile_Ng${k}u.ini" "Run shapepipe (tile: ngmix+galsim $k)" & + done + wait + VERBOSE=1 + +fi + +## Create final catalogues (offline) +(( do_job= $job & 64 )) +if [[ $do_job != 0 ]]; then + + cat $SP_CONFIG/config_merge_sep_cats_template.ini | \ + perl -ane \ + 's/(N_SPLIT_MAX =) X/$1 '$nsh_jobs'/; print' \ + > $SP_CONFIG_MOD/config_merge_sep_cats.ini + + ### Merge separated shapes catalogues + command_sp "shapepipe_run -c $SP_CONFIG_MOD/config_merge_sep_cats.ini" "Run shapepipe (tile: merge sep cats)" "$VERBOSE" "$ID" + + ### Merge all relevant information into final catalogue + command_sp "shapepipe_run -c $SP_CONFIG/config_make_cat_$psf.ini" "Run shapepipe (tile: create final cat $psf)" "$VERBOSE" "$ID" + +fi + +## Upload results (online) +(( do_job= $job & 128 )) +if [[ $do_job != 0 ]]; then + + ### module and pipeline log files + upload_logs "$ID" "$VERBOSE" + + ### Final shape catalog + ### pipeline_flags are the tile masks, for random cats + ### SETools masks (selection), stats and plots + ### ${psf}_interp_exp for diagnostics, validation with leakage, + ### validation with residuals, rho stats + + NAMES=( + "final_cat" + "pipeline_flag" + "setools_mask" + "setools_stat" + "setools_plot" + ) + DIRS=( + "*/make_cat_runner/output" + "*/mask_runner_run_1/output" + "*/setools_runner/output/mask" + "*/setools_runner/output/stat" + "*/setools_runner/output/plot" + ) + PATTERNS=( + "final_cat-*" + "pipeline_flag-???-???*" + "*" + "*" + "*" + ) + + # PSF validation + pattern="validation_psf-*" + if [ "$psf" == "psfex" ]; then + name="psfex_interp_exp" + dir="*/psfex_interp_runner/output" + else + name="mccd_fit_val_runner" + dir="*/mccd_fit_val_runner/output" + fi + upl=$output_rel/$dir/$pattern + upload "$name" "$ID" "$VERBOSE" "${upl[@]}" + + for n in "${!NAMES[@]}"; do + name=${NAMES[$n]} + dir=${DIRS[$n]} + pattern=${PATTERNS[$n]} + upl=$output_rel/$dir/$pattern + upload "$name" "$ID" "$VERBOSE" "${upl[@]}" + done + +fi diff --git a/example/cfis_simu/mask_default/MEGAPRIME_star_i_13.8.reg b/example/cfis_simu/mask_default/MEGAPRIME_star_i_13.8.reg new file mode 100644 index 000000000..4e4164aaf --- /dev/null +++ b/example/cfis_simu/mask_default/MEGAPRIME_star_i_13.8.reg @@ -0,0 +1,24 @@ +-11.5 68 +-6 186.5 +7 188 +10 64.5 +31 55 +50 38.5 +56.5 11.5 +188 8 +192 -4 +59.5 -11.5 +45 -33 +13.5 -64 +5 -154 +-6 -155 +-11 -64.5 +-40 -44.5 +-51.5 -30.5 +-62.5 -22.5 +-68 -9.5 +-177 -2 +-176 3 +-78 12.5 +-67.5 14.5 +-38.5 50 diff --git a/example/cfis_simu/mask_default/Messier_catalog.npy b/example/cfis_simu/mask_default/Messier_catalog.npy new file mode 100644 index 0000000000000000000000000000000000000000..ef07eb032b08de4fcf508418524692e27f92ad75 GIT binary patch literal 4209 zcmb7{dvKIj6~H$S0z_V+Av_zF=Wf!F0D%A@VJ{fCEf+Q}Ge}K(fi%99nrA zDunWq77DdgDz+6YRTR<6s3U8&j-3Igj&%@bimd}oA2U?zlbKdM_uP9w(m(ve`$y*c zzCFM5y62pGb0i#Dx@=XB?^WN{Ks?dak_puMR|f+dThsACg+H)u`P4vJg+CbRYTc6H z4~^zMo@mjpb;;T0Jrn)RYq*17Tj|%eB$n*RU?!Sg*O7@Qw1q{{wyp$y?@C2G6Z9UO zJ*|SwZ1?}atFSw_CB3P=b8}@&M!PQkRQogQ9WJxR1Qh>397tE&bDwclCSdu1(AH6 z4(J=nqclLjNNy$y{Uf>I4k$$U+;$icOckc`Be|`!t%iZDp)MQ_Fa8fL{-b;tQzLp( z1zK|XR4X~i+6ssD2bS^mr21)@q|-L|e`)L2lj@%utcLWY`f8xj0Yf~cz08Nmysu}I z@{^g-7~8uRih{w2Z!HWBN-@I6ONt@pAt6OgeuG|8G~c*H>$1v0xQBsaDf~%ZQ5pK+ zj9#xu(RJZAt&dbL!Y~#qk)qmYi%L-!8?ToXsYiGI;Jwj}Di2{ei;a+?!V|0AWsRl> zym+Os9#lTUNERCeCHYt zJUw6aL%5fLQZM+Z%ud_-6Iwr&qT_?AH)5Y0Q~eRfvY5YD%-O+3yrf8%k}`2kQ5lS5 zF$!?}vw9tm%8M`a(@7E=S+VZ$>vz-ugb6G*QHqIP%nRl)Kw>5JofNeih%kx8CQH%J ziDe7S6Z!TxZ4=cXgaC_C$oH}-GAe=*UV1+mP=gW5Sgf4nY({85j5bP5FwOf$skxcg z`ew}uH3Z>41}X@U&gz10ej=di1-q4`b^hq(-Jdoa+e?F#{-Xl{Y#R$_Fm@dV%C0vB0w`Q0Pu=9N?r10aa z1fiP6W{_UL)7z_%e`NK-A8(x7p+->k!%PNhq!_BzUb;+rXK_@tft|MwtqK197itW` zEEbzBMTsX?^IN<3T|d4!Y5&KoR4Kw77ON%ms|DMaqS5$4ebivn6}t8M9V&xgsj&!i z8K@&*oT+IkM%@MMhIoJxJ1e4yYTsCB3-YHfhMU}t3w%~Us)i{I@1A>5M z-PR@B7L@6soDj-%^Uc>N)_z{GGL!si)iAfUj; z5chgC? z3g;oLX0bJ-x6I~7j4@k7dKc!~37<-tWQGvdGVllib}C9S%nNnqSzCL_=S?yN!a4@l z6EN0g|6g7*%bn5qnc^)}C2BrGlz|ul+q+-jSP-A>&68b=j-t$X$xCiGfE6@H@}#1%&`}s!}C4|3xRHS%ncEW8jNY^fzTg z8JXpd^5&~XtPx=|i*1pj&>|L+d5Nq!9g?sS0L0-4w@4|Wsp3qZx=0U6~aLVzCyqRm{F~3&hHc>Jfya3>+iC-sHUVhk$^KK6XW4(DKwegl8D|DgmX=&0@1}8gR!+><@H9 z+WAAZ9^qLAjuT*e#Csq>?XndVKW$FmD8h3Le2oCVEeJOk2$!g6{6`KDwc_*QyqTuQPCx0DJ5Z>D8!r%S;}ikXzqWafEL$@B#sK&c5wX z9YclwMt!znzPT4B5ME^9B?1bpOTA8Mbw^hpRnUe7=8}*^_$C9V2=Fdu-YK1(=oR%* zt|gU1IL*MfJ`;oX=kB5NT zfba?f-uzXxoJl@$H4aq@J{Kw+tpw#gl=-AJ5(Csd;(*Y{{>v*ks<&9 literal 0 HcmV?d00001 diff --git a/example/cfis_simu/mask_default/Messier_catalog_updated.fits b/example/cfis_simu/mask_default/Messier_catalog_updated.fits new file mode 100644 index 0000000000000000000000000000000000000000..6a9f00096170565aeb7fab3429c2256ce56f3533 GIT binary patch literal 8640 zcmeHL4NO&K82bxk?Xcg61^5lKgn(d%puWZoviN(qOUV;yoAdgbQ9S23R5C zGJc%mUqCidTB!L;nwUE8!IV-Emzk_l)0xbfKNvc7R`!19<}PlRM&quncFy*U!+YNM z`JV52-?M$^Ch6l6Vxt8?D|on!!gOJNj?I!|&(0GZIf71aOcL@OCY#x0H+#s(5YrnI z^eKJtg(9EHZZ{PQW|PAtI0|zm&n)h!0aEly_^(HOFCm{TKRZLR3ptjD%+_qlmS@ee z<+(|E-9@JuqYY7g@ELn0_VZRD>u0W-raGWHpgN#BpgN#BpgN#B@ZWcUA19Oa@dm9B z$n*vyu-NFpUb~tuWLRw`d!gVkWn@W$RN!zOPJ5+1di$@QpJ)8@^Rsdu5B7Y14xWX4 zS&}W&v4Ee)%@0rF0_OL1DSR_L^MwZY!H4;MT?t}*vH{QW{rFzUwCCjK3b`h`DO++# zcF*4nulyY!*XREJQ20EvxYZhU`smoGB+vRn9^rG1jKwNtnfqonipd7O(vLv1l&P%K zd;Z)D_w!ESQ~KdWJ`L|jpvgWz+iDYpf$N*;MLuI{LbS_2yUFFz!1U?j6XRTb_*Jc3 z1LNcR9`<9t7x=h77oYd^x%!)DEt2Npr~knA%k{bVyr<7KFN(fYZ|HOJc~4)6GS3UG zHswc^f&1s;18>Zq`uoOTE~2Q~q|Mla|%g za-h=JE%N?j_uw*?bnuLd%4718+1H`mV&Nd-x*iGk9UB7p&}C4$PlbH^_CmVeV&Nd- z=89JNK<*p#3k)C#Ou1FXUhvhhA8^?Mtb-}voMsd9Z@}Xk4L!{R2OH5KblZ)dP$=zM!+^*|xtz<#td_j+GQ1-&6ZGat%$AEx3wsX?S2kT*O z(P(-PbvTh(obuFT5Z{>yK3MWT-;4Ig4*6`)85)KG1QE-xCN>W;=W>HMh*)Vk)ja6M z@syJyu$7@FVSU62dK5DdMBK3RxExb`isC~K0*QVOCn9^$ zbp(OdhJ(xyr{#o-Fcz?5&!N=z7J3m$omj$lnD%Km2LvbsqXagOsg}PA-bQ25LIe>V zY_+_lgL<|@I z07LL-iY?$qV<2@4R4q?dbnI3#Dr+G=U=KWr-9NxdBlb3dj*Wz&SaOD!L_8P^mIHNs zdT16GHv7tAi0Nvf^(agkZEeVSNc<=n#-hoUN=9c0WOjG+Cb?dqlKPu$YDEYqwBwk(z^jfXBY2yG-{#>NlWyeBp( z@5@r2p?zSM!|o1OUcz)9@V|8#^oBHrL)mTU;l)flYcOm;Vdr^9f&XuELZ^<7!rdZ> z7d$Tc4;qc|FXe?ZLlMI-okBI`F@A;7=F| BE!zM9 literal 0 HcmV?d00001 diff --git a/example/cfis_simu/mask_default/default.ww b/example/cfis_simu/mask_default/default.ww new file mode 100644 index 000000000..c2797f904 --- /dev/null +++ b/example/cfis_simu/mask_default/default.ww @@ -0,0 +1,40 @@ +#--------------------------------- Weights ------------------------------------ + +WEIGHT_NAMES weightin.fits # Filename(s) of the input WEIGHT map(s) + +WEIGHT_MIN 0. # Pixel below those thresholds will be flagged +WEIGHT_MAX 1000. # Pixels above those thresholds will be flagged +WEIGHT_OUTFLAGS 1 # FLAG values for thresholded pixels + +#---------------------------------- Flags ------------------------------------- + +FLAG_NAMES flagin.fits # Filename(s) of the input FLAG map(s) + +FLAG_WMASKS 0xff # Bits which will nullify the WEIGHT-map pixels +FLAG_MASKS 0x01 # Bits which will be converted as output FLAGs +FLAG_OUTFLAGS 2 # Translation of the FLAG_MASKS bits + +#---------------------------------- Polygons ---------------------------------- + +POLY_NAMES "" # Filename(s) of input DS9 regions +POLY_OUTFLAGS # FLAG values for polygon masks +POLY_OUTWEIGHTS 0.0 # Weight values for polygon masks +POLY_INTERSECT Y # Use inclusive OR for polygon intersects (Y/N)? + +#---------------------------------- Output ------------------------------------ + +OUTWEIGHT_NAME "w.fits" # Output WEIGHT-map filename +OUTFLAG_NAME flag.fits # Output FLAG-map filename + +#----------------------------- Miscellaneous --------------------------------- + +GETAREA N # Compute area for flags and weights (Y/N)? +GETAREA_WEIGHT 0.0 # Weight threshold for area computation +GETAREA_FLAGS 1 # Bit mask for flag pixels not counted in area +MEMORY_BUFSIZE 256 # Buffer size in lines +VERBOSE_TYPE NORMAL # can be QUIET, NORMAL or FULL +WRITE_XML N # Write XML file (Y/N)? +XML_NAME ww.xml # Filename for XML output +XSL_URL file:///usr/local/share/weightwatcher/ww.xsl + # Filename for XSL style-sheet +NTHREADS 1 # 1 single thread \ No newline at end of file diff --git a/example/cfis_simu/mask_default/halo_mask.reg b/example/cfis_simu/mask_default/halo_mask.reg new file mode 100644 index 000000000..c44f25167 --- /dev/null +++ b/example/cfis_simu/mask_default/halo_mask.reg @@ -0,0 +1,50 @@ + 274.66813 -1.25966 + 272.54579 32.47406 + 266.21222 65.67579 + 255.76731 97.82190 + 241.37579 128.40544 + 223.26462 156.94408 + 201.71942 182.98775 + 177.07997 206.12573 + 149.73486 225.99312 + 120.11532 242.27660 + 88.68848 254.71937 + 55.94996 263.12519 + 22.41606 267.36151 + -11.38436 267.36151 + -44.91826 263.12519 + -77.65678 254.71937 +-109.08362 242.27660 +-138.70315 225.99312 +-166.04827 206.12573 +-190.68772 182.98775 +-212.23292 156.94408 +-230.34409 128.40544 +-244.73561 97.82190 +-255.18052 65.67579 +-261.51409 32.47406 +-263.63643 -1.25966 +-261.51409 -34.99339 +-255.18052 -68.19511 +-244.73561 -100.34123 +-230.34409 -130.92476 +-212.23292 -159.46341 +-190.68772 -185.50708 +-166.04827 -208.64506 +-138.70315 -228.51245 +-109.08362 -244.79593 + -77.65678 -257.23870 + -44.91826 -265.64452 + -11.38436 -269.88084 + 22.41606 -269.88084 + 55.94996 -265.64452 + 88.68848 -257.23870 + 120.11532 -244.79593 + 149.73486 -228.51245 + 177.07997 -208.64506 + 201.71942 -185.50708 + 223.26462 -159.46341 + 241.37579 -130.92476 + 255.76731 -100.34123 + 266.21222 -68.19511 + 272.54579 -34.99339 diff --git a/example/cfis_simu/mask_default/ngc_cat.fits b/example/cfis_simu/mask_default/ngc_cat.fits new file mode 100644 index 0000000000000000000000000000000000000000..f51546da7fc88ae1ca919a3c13882fe1a7df6768 GIT binary patch literal 201600 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

4h9YH;BjCK1aktyi9r? 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 0 +MAG_AUTO < 21 +FWHM_IMAGE > 0.3 / 0.187 +FWHM_IMAGE < 1.5 / 0.187 +FLAGS == 0 +IMAFLAGS_ISO == 0 +NO_SAVE + +[MASK:flag] +FLAGS == 0 +IMAFLAGS_ISO == 0 +NO_SAVE + + +[MASK:star_selection] +# Star selection using the FWHM mode +MAG_AUTO > 18. +MAG_AUTO < 22. +FWHM_IMAGE <= mode(FWHM_IMAGE{preselect}) + 0.2 +FWHM_IMAGE >= mode(FWHM_IMAGE{preselect}) - 0.2 +FLAGS == 0 +IMAFLAGS_ISO == 0 +#CLASS_STAR != 0 + +[MASK:fwhm_mag_cut] +FWHM_IMAGE > 0 +FWHM_IMAGE < 40 +MAG_AUTO < 35 +FLAGS == 0 +IMAFLAGS_ISO == 0 +NO_SAVE + +# Split the 'star_selection' sample into +# two random sub-samples with ratio 80/20 +[RAND_SPLIT:star_split] +RATIO = 20 +MASK = star_selection + +# The following selection is only used for plotting + +[PLOT:size_mag] +TYPE = plot +FORMAT = png +X_1 = FWHM_IMAGE{fwhm_mag_cut} +Y_1 = MAG_AUTO{fwhm_mag_cut} +X_2 = FWHM_IMAGE{star_selection} +Y_2 = MAG_AUTO{star_selection} +MARKER_1 = + +MARKER_2 = . +MARKERSIZE_1 = 3 +MARKERSIZE_2 = 3 +LABEL_1 = All +LABEL_2 = "Stars, mean FWHM: @mean(FWHM_IMAGE{star_selection})*0.187@ arcsec" +TITLE = "Stellar locus" +XLABEL = "FWHM (pix)" +YLABEL = Mag + +[PLOT:hist_mag_stars] +TYPE = hist +FORMAT = png +Y = MAG_AUTO{star_selection} +BIN = 20 +LABEL = "stars" +XLABEL = "Magnitude" +YLABEL = "Number" +TITLE = "Magnitude of stars" + +[PLOT:fwhm_field] +TYPE = scatter +FORMAT = png +X = X_IMAGE{star_selection} +Y = Y_IMAGE{star_selection} +SCATTER = FWHM_IMAGE{star_selection}*0.186 +MARKER = . +LABEL = "FWHM (arcsec)" +TITLE = "FWHM of stars" +XLABEL = "X (pix)" +YLABEL = "Y (pix)" + +[PLOT:mag_star_field] +TYPE = scatter +FORMAT = png +X = X_IMAGE{star_selection} +Y = Y_IMAGE{star_selection} +SCATTER = MAG_AUTO{star_selection} +MARKER = . +LABEL = "Magnitude" +TITLE = "Magnitude of stars" +XLABEL = "X (pix)" +YLABEL = "Y (pix)" + +[STAT:star_stat] +"Nb objects full cat" = len(FWHM_IMAGE) +"Nb objects not masked" = len(FWHM_IMAGE{flag}) +"Nb stars" = len(FWHM_IMAGE{star_selection}) +"stars/deg^2" = len(FWHM_IMAGE{star_selection})/4612./0.187*3600.*1./2048./0.187*3600. +"Mean star fwhm selected (arcsec)" = mean(FWHM_IMAGE{star_selection})*0.187 +"Standard deviation fwhm star selected (arcsec)" = std(FWHM_IMAGE{star_selection})*0.187 +"Mode fwhm used (arcsec)" = mode(FWHM_IMAGE{preselect})*0.187 +"Min fwhm cut (arcesec)" = mode(FWHM_IMAGE{preselect})*0.187-0.1*0.187 +"Max fwhm cut (arcsec)" = mode(FWHM_IMAGE{preselect})*0.187+0.1*0.187 diff --git a/example/cfis_simu/tile_numbers.txt b/example/cfis_simu/tile_numbers.txt new file mode 100644 index 000000000..3c0ce178a --- /dev/null +++ b/example/cfis_simu/tile_numbers.txt @@ -0,0 +1 @@ +224-295 From ea089d6633e1840ec005925a4ead4b9076f0f600 Mon Sep 17 00:00:00 2001 From: fabianhervaspeters <87416002+fabianhervaspeters@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:10:59 +0100 Subject: [PATCH 17/41] Delete .DS_Store --- example/cfis_simu/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 example/cfis_simu/.DS_Store diff --git a/example/cfis_simu/.DS_Store b/example/cfis_simu/.DS_Store deleted file mode 100644 index 6b946e67e4da54b4cef0892f1b9d546e08938660..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOG*Pl5UtWE0T*T|WYag0++Y&M6XXIi8PLUq9*EiZNjy!qg5ZUG^@%cOz>SDV z6?DDs`t;|)bWafxulDVNXhuX+G(ncmh=_UAb>_hrK-M|-^wjP)U6XS+GSOc&$=)w1 z6LwC$=;QuzprNCCSgbdB+v_Q=pKrhVx4EvHE;q1)tulXkJ1kFQ+HYg}$Io@27-ZL;0GCyCk`^bG7KFI1Ovgq2Lp0HBs9Uwu^8&r0i`7Xa00Um`cg|sPI9aq ziy=G^wp5^{vX>Za>98k{s~n4=r4xJc!M^gbcwt=~^Ct}_t_(v51Hr(MfpZ(qw1Ml`P+JOJb7yq+C7?x#1-j4&>#E+U?BI%jXKSrq>s4D Wu^7rMV%KzF{0Jx^p@M;5VBj5;6*LI| From c3c4aeebb0e0685a05493c8d894b2ea47638c985 Mon Sep 17 00:00:00 2001 From: fabianhervaspeters <87416002+fabianhervaspeters@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:11:05 +0100 Subject: [PATCH 18/41] Delete ._.DS_Store --- example/cfis_simu/._.DS_Store | Bin 4096 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 example/cfis_simu/._.DS_Store diff --git a/example/cfis_simu/._.DS_Store b/example/cfis_simu/._.DS_Store deleted file mode 100644 index 7a2262ee0b2dff251292f5b68503b7de8fc90439..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIhYCu0iY;W;207T z#K0i552Ayi0;{4?!O;*H4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5TJ4hFapg3 zVK9&j$;d2LC`v8PFD*(=RY=P(%2vqCD@n~O$;{77%*m-#$Vp8rQAo;3%*zILb)mY3 QG==JaxL0Ht Date: Mon, 6 Mar 2023 14:46:20 +0100 Subject: [PATCH 19/41] Delete config_tile.mask As Martin suggested this file is not needed when running the simulation as config_tile.mask_simu is used --- example/cfis_simu/config_tile.mask | 90 ------------------------------ 1 file changed, 90 deletions(-) delete mode 100644 example/cfis_simu/config_tile.mask diff --git a/example/cfis_simu/config_tile.mask b/example/cfis_simu/config_tile.mask deleted file mode 100644 index 4381d61b9..000000000 --- a/example/cfis_simu/config_tile.mask +++ /dev/null @@ -1,90 +0,0 @@ -# Mask module config file for tiles - -## Paths to executables -[PROGRAM_PATH] - -WW_PATH = ww -WW_CONFIG_FILE = $SP_CONFIG/mask_default/default.ww - -# Indicate cds client executable if no external star catalogue is available -# (e.g. no internet access on run nodes) -CDSCLIENT_PATH = findgsc2.2 - -## Border parameters -[BORDER_PARAMETERS] - -BORDER_MAKE = False - -BORDER_WIDTH = 0 -BORDER_FLAG_VALUE = 4 - - -## Halo parameters -[HALO_PARAMETERS] - -HALO_MAKE = True - -HALO_MASKMODEL_PATH = $SP_CONFIG/mask_default/halo_mask.reg -HALO_MAG_LIM = 13. -HALO_SCALE_FACTOR = 0.05 -HALO_MAG_PIVOT = 13.8 -HALO_FLAG_VALUE = 2 -HALO_REG_FILE = halo.reg - - -## Diffraction pike parameters -[SPIKE_PARAMETERS] - -SPIKE_MAKE = True - -SPIKE_MASKMODEL_PATH = $SP_CONFIG/mask_default/MEGAPRIME_star_i_13.8.reg -SPIKE_MAG_LIM = 18. -SPIKE_SCALE_FACTOR = 0.3 -SPIKE_MAG_PIVOT = 13.8 -SPIKE_FLAG_VALUE = 128 -SPIKE_REG_FILE = spike.reg - - -## Messier parameters -[MESSIER_PARAMETERS] - -MESSIER_MAKE = True - -MESSIER_CAT_PATH = $SP_CONFIG/mask_default/Messier_catalog_updated.fits -MESSIER_PIXEL_SCALE = 0.187 -MESSIER_SIZE_PLUS = 0. -MESSIER_FLAG_VALUE = 16 - -## NGC mask -[NGC_PARAMETERS] - -NGC_MAKE = True - -NGC_CAT_PATH = $SP_CONFIG/mask_default/ngc_cat.fits -NGC_SIZE_PLUS = 0. -NGC_FLAG_VALUE = 32 - - -## External flag -[EXTERNAL_FLAG] - -EF_MAKE = False - - -## Missing data parameters -[MD_PARAMETERS] - -MD_MAKE = False - -MD_THRESH_FLAG = 0.3 -MD_THRESH_REMOVE = 0.75 -MD_REMOVE = False - - -## Other parameters -[OTHER] - -KEEP_REG_FILE = False -KEEP_INDIVIDUAL_MASK = False - -TEMP_DIRECTORY = .temp_tiles From 91842a99d21fde163c4639b43ea76af0c59627c1 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 4 Apr 2023 16:04:54 +0200 Subject: [PATCH 20/41] mccd runner: DEC -> DES for rho stats mode --- shapepipe/modules/mccd_plots_runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shapepipe/modules/mccd_plots_runner.py b/shapepipe/modules/mccd_plots_runner.py index 7fd95b691..615b2e11a 100644 --- a/shapepipe/modules/mccd_plots_runner.py +++ b/shapepipe/modules/mccd_plots_runner.py @@ -129,9 +129,9 @@ def mccd_plots_runner( ) warnings.warn(msg) w_log.info(msg) - elif rho_stat_plot_style != 'HSC' and rho_stat_plot_style != 'DEC': + elif rho_stat_plot_style != 'HSC' and rho_stat_plot_style != 'DES': msg = ( - 'The rho stat definition should be HSC or DEC. An unknown' + 'The rho stat definition should be HSC or DES. An unknown' + ' definition was used. Rho stat calculation aborted.' ) warnings.warn(msg) From 430aaa7d279bf9fcd487009aef598a848e6dc7da Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 10 May 2023 12:58:15 +0200 Subject: [PATCH 21/41] added skymapper (for spectro plotting) --- environment.yml | 1 + scripts/jupyter/plot_spectro_areas.ipynb | 38 +++++++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/environment.yml b/environment.yml index 24f6dfd5f..7cb67a3c6 100644 --- a/environment.yml +++ b/environment.yml @@ -23,6 +23,7 @@ dependencies: - reproject==0.8 - sip_tpv==1.1 - sf_tools==2.0.4 + - skymapper==0.4.3 - sqlitedict==2.0.0 - termcolor==1.1.0 - tqdm==4.63.0 diff --git a/scripts/jupyter/plot_spectro_areas.ipynb b/scripts/jupyter/plot_spectro_areas.ipynb index b881d208c..b41326a17 100644 --- a/scripts/jupyter/plot_spectro_areas.ipynb +++ b/scripts/jupyter/plot_spectro_areas.ipynb @@ -9,9 +9,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Warning: surveys missing because pymangle is not installed\n" + ] + } + ], "source": [ "import os\n", "import sys\n", @@ -19,7 +27,7 @@ "import numpy as np\n", "import pylab as plt\n", "from astropy.io import fits\n", - "from shapepipe.utilities import cfis\n", + "from cs_util import cfis\n", "from astropy.coordinates import SkyCoord, match_coordinates_sky\n", "from astropy import units as u\n", "import pandas as pd\n", @@ -45,11 +53,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ - "# Download spectroscopic data:\n", + "## Download spectroscopic data:\n", "# - 3DHST (AEGIS and GOODS-N)\n", "# http://monoceros.astro.yale.edu/RELEASE_V4.1.5/3dhst.v4.1.5.master.fits.gz\n", "# (Need to first register at https://3dhst.research.yale.edu/signup.php)\n", @@ -73,6 +81,8 @@ "# http://sdss.physics.nyu.edu/vagc/#download\n", "# - AGES:\n", "# http://vizier.cfa.harvard.edu/viz-bin/VizieR-3?-source=J/ApJS/200/8/sources\n", + "# - DESI:\n", + "# - Iron https://data.desi.lbl.gov/public/dr1/vac/lsdr9-photometry/iron/v1.0/observed-targets/\n", "\n", "# Other data\n", "# - HSC Hectomap field, star catalogue\n", @@ -91,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -198,7 +208,7 @@ "# 'eBOSSLRGCMASS16-N', 'eBOSSLRGCMASS16-S', 'eBOSSELG16-N',\n", "# 'eBOSSQSO16-N', 'eBOSSQSO16-S']\n", "\n", - "use = ['HectoMap-HSC-stars']\n", + "use = ['DESI-Iron']\n", "\n", "do_SDSS = False\n", "\n", @@ -285,7 +295,13 @@ "if 'DECaLS-groups'in use:\n", " surveys.append(Survey.from_fits('DECaLS-groups', 'cyan',\n", " '{}/DESI_NGC_group_cut.txt.fits'.format(cat_home),\n", - " key_ra='RA[deg]', key_dec='DEC[deg]'))" + " key_ra='RA[deg]', key_dec='DEC[deg]'))\n", + " \n", + "if 'DESI-Iron'in use:\n", + " surveys.append(Survey.from_fits('DESI', 'cyan',\n", + " '{}/.fits'.format(cat_home),\n", + " key_ra='RA[deg]', key_dec='DEC[deg]'))\n", + " " ] }, { @@ -628,9 +644,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "sp_validation", "language": "python", - "name": "python3" + "name": "sp_validation" }, "language_info": { "codemirror_mode": { @@ -642,7 +658,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.8.0" } }, "nbformat": 4, From 0d6ae7f59c7ad27d00659d8aaaed8a7447ab5e66 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Mon, 15 May 2023 14:33:33 +0200 Subject: [PATCH 22/41] Updated ME_IMAGE_DIR doc entry --- shapepipe/modules/vignetmaker_package/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shapepipe/modules/vignetmaker_package/__init__.py b/shapepipe/modules/vignetmaker_package/__init__.py index 56a09b226..549e74e1a 100644 --- a/shapepipe/modules/vignetmaker_package/__init__.py +++ b/shapepipe/modules/vignetmaker_package/__init__.py @@ -37,7 +37,9 @@ Output file name prefix(es) ME_IMAGE_DIR : list Input directories for single-exposure flags, images, weights, and - SExtractor background images, for multi-epoch processing + SExtractor background images, for multi-epoch processing. + Provide a list of directories, one for each image matching + ME_IMAGE_PATTERN, or one single directory for all images. ME_IMAGE_PATTERN : list Input file name patterns for flag, image, weight, and SExtractor background files, for multi-epoch processing From b50eb65d76c11e020a5f941e6cd8d35334c1cfe5 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Mon, 15 May 2023 15:24:33 +0200 Subject: [PATCH 23/41] Clarified example of multiple module runs in API doc --- docs/source/configuration.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/configuration.md b/docs/source/configuration.md index 2c3d2e99e..3336123c1 100644 --- a/docs/source/configuration.md +++ b/docs/source/configuration.md @@ -200,6 +200,9 @@ where ``X`` is an integer greater than or equal to ``1``. This feature can be co ```ini +[EXECUTION] +MODULE = module_a_runner, module_b_runner, module_b_runner + [MODULE_A_RUNNER_RUN_1] ... From 873e7a64dcb394bf968422033748477dddb1a161 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 17 May 2023 09:17:43 +0200 Subject: [PATCH 24/41] Corrected documentation where module names of last runs are read in module runner section (instead of dir names) --- shapepipe/modules/mccd_interp_runner.py | 1 - shapepipe/modules/mccd_package/__init__.py | 3 ++- shapepipe/modules/psfex_interp_package/__init__.py | 9 +++++---- shapepipe/modules/vignetmaker_package/__init__.py | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shapepipe/modules/mccd_interp_runner.py b/shapepipe/modules/mccd_interp_runner.py index 49780bec6..4856e562f 100644 --- a/shapepipe/modules/mccd_interp_runner.py +++ b/shapepipe/modules/mccd_interp_runner.py @@ -53,7 +53,6 @@ def mccd_interp_runner( module_config_sec, 'PSF_MODEL_SEPARATOR' ) - # psfcat_path, galcat_path = input_file_list galcat_path = input_file_list[0] # verify that the MCCD model exists diff --git a/shapepipe/modules/mccd_package/__init__.py b/shapepipe/modules/mccd_package/__init__.py index 2d7364d7c..dc6416c43 100644 --- a/shapepipe/modules/mccd_package/__init__.py +++ b/shapepipe/modules/mccd_package/__init__.py @@ -123,7 +123,8 @@ GET_SHAPES: bool Calculate PSF model shapes and save to output if ``True`` PSF_MODEL_DIR: str - Input directories for the fitted MCCD PSF model files + Module name of last run producing the fitted MCCD PSF model files. + The specifier "last:" is not required PSF_MODEL_PATTERN: str Pattern of the fitted PSF models PSF_MODEL_SEPARATOR: str diff --git a/shapepipe/modules/psfex_interp_package/__init__.py b/shapepipe/modules/psfex_interp_package/__init__.py index 5569be894..afda4d2e2 100644 --- a/shapepipe/modules/psfex_interp_package/__init__.py +++ b/shapepipe/modules/psfex_interp_package/__init__.py @@ -32,10 +32,11 @@ Threshold of stars under which the PSF is not interpolated CHI2_THRESH : int Threshold for chi squared (:math:`\chi^2`) -ME_DOT_PSF_DIR : list - Input directories for PSFEx PSF model files, for multi-epoch processing -ME_DOT_PSF_PATTERN : list - Input file name patterns for PSFEx PSF model files, for multi-epoch +ME_DOT_PSF_DIR : str + Module name of last run producing PSFEx PSF model files, for multi-epoch + processing. The specifier "last:" is not required +ME_DOT_PSF_PATTERN : str + Input file name pattern for PSFEx PSF model files, for multi-epoch processing ME_LOG_WCS : str Path to world coordinate system log file (``*sqlite``) diff --git a/shapepipe/modules/vignetmaker_package/__init__.py b/shapepipe/modules/vignetmaker_package/__init__.py index 56a09b226..a61e83c27 100644 --- a/shapepipe/modules/vignetmaker_package/__init__.py +++ b/shapepipe/modules/vignetmaker_package/__init__.py @@ -36,8 +36,9 @@ PREFIX : str or list Output file name prefix(es) ME_IMAGE_DIR : list - Input directories for single-exposure flags, images, weights, and - SExtractor background images, for multi-epoch processing + Module names of last run producing single-exposure flags, images, weights, + and SExtractor background images, for multi-epoch processing. The specifier + "last:" is not required ME_IMAGE_PATTERN : list Input file name patterns for flag, image, weight, and SExtractor background files, for multi-epoch processing From 14d7b2e826cfd36cd17ceb863ed875df497afcdf Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 17 May 2023 10:25:15 +0200 Subject: [PATCH 25/41] reset environment and jupyter notebook to develop --- environment.yml | 1 - scripts/jupyter/plot_spectro_areas.ipynb | 38 +++++++----------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/environment.yml b/environment.yml index 7cb67a3c6..24f6dfd5f 100644 --- a/environment.yml +++ b/environment.yml @@ -23,7 +23,6 @@ dependencies: - reproject==0.8 - sip_tpv==1.1 - sf_tools==2.0.4 - - skymapper==0.4.3 - sqlitedict==2.0.0 - termcolor==1.1.0 - tqdm==4.63.0 diff --git a/scripts/jupyter/plot_spectro_areas.ipynb b/scripts/jupyter/plot_spectro_areas.ipynb index b41326a17..b881d208c 100644 --- a/scripts/jupyter/plot_spectro_areas.ipynb +++ b/scripts/jupyter/plot_spectro_areas.ipynb @@ -9,17 +9,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Warning: surveys missing because pymangle is not installed\n" - ] - } - ], + "outputs": [], "source": [ "import os\n", "import sys\n", @@ -27,7 +19,7 @@ "import numpy as np\n", "import pylab as plt\n", "from astropy.io import fits\n", - "from cs_util import cfis\n", + "from shapepipe.utilities import cfis\n", "from astropy.coordinates import SkyCoord, match_coordinates_sky\n", "from astropy import units as u\n", "import pandas as pd\n", @@ -53,11 +45,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "## Download spectroscopic data:\n", + "# Download spectroscopic data:\n", "# - 3DHST (AEGIS and GOODS-N)\n", "# http://monoceros.astro.yale.edu/RELEASE_V4.1.5/3dhst.v4.1.5.master.fits.gz\n", "# (Need to first register at https://3dhst.research.yale.edu/signup.php)\n", @@ -81,8 +73,6 @@ "# http://sdss.physics.nyu.edu/vagc/#download\n", "# - AGES:\n", "# http://vizier.cfa.harvard.edu/viz-bin/VizieR-3?-source=J/ApJS/200/8/sources\n", - "# - DESI:\n", - "# - Iron https://data.desi.lbl.gov/public/dr1/vac/lsdr9-photometry/iron/v1.0/observed-targets/\n", "\n", "# Other data\n", "# - HSC Hectomap field, star catalogue\n", @@ -101,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -208,7 +198,7 @@ "# 'eBOSSLRGCMASS16-N', 'eBOSSLRGCMASS16-S', 'eBOSSELG16-N',\n", "# 'eBOSSQSO16-N', 'eBOSSQSO16-S']\n", "\n", - "use = ['DESI-Iron']\n", + "use = ['HectoMap-HSC-stars']\n", "\n", "do_SDSS = False\n", "\n", @@ -295,13 +285,7 @@ "if 'DECaLS-groups'in use:\n", " surveys.append(Survey.from_fits('DECaLS-groups', 'cyan',\n", " '{}/DESI_NGC_group_cut.txt.fits'.format(cat_home),\n", - " key_ra='RA[deg]', key_dec='DEC[deg]'))\n", - " \n", - "if 'DESI-Iron'in use:\n", - " surveys.append(Survey.from_fits('DESI', 'cyan',\n", - " '{}/.fits'.format(cat_home),\n", - " key_ra='RA[deg]', key_dec='DEC[deg]'))\n", - " " + " key_ra='RA[deg]', key_dec='DEC[deg]'))" ] }, { @@ -644,9 +628,9 @@ ], "metadata": { "kernelspec": { - "display_name": "sp_validation", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "sp_validation" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -658,7 +642,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.0" + "version": "3.9.7" } }, "nbformat": 4, From 320bc250b028ee6f7e306ac457d58ed74f919b09 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 27 Jun 2023 09:13:48 +0200 Subject: [PATCH 26/41] added spaces --- shapepipe/modules/mask_package/mask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapepipe/modules/mask_package/mask.py b/shapepipe/modules/mask_package/mask.py index fad3a0187..69a1c3c97 100644 --- a/shapepipe/modules/mask_package/mask.py +++ b/shapepipe/modules/mask_package/mask.py @@ -1179,7 +1179,7 @@ def _build_final_mask( ) external_flag.open() if final_mask is not None: - final_mask=final_mask.astype(np.int16, copy=False) + final_mask = final_mask.astype(np.int16, copy=False) final_mask += external_flag.get_data()[:, :] else: final_mask = external_flag.get_data()[:, :] From 82efb01e15e77df6725f5c22d46448b0b4d5ed2f Mon Sep 17 00:00:00 2001 From: fabianhervaspeters Date: Tue, 18 Jul 2023 15:23:36 +0200 Subject: [PATCH 27/41] added doctsring --- shapepipe/modules/find_exposures_package/find_exposures.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shapepipe/modules/find_exposures_package/find_exposures.py b/shapepipe/modules/find_exposures_package/find_exposures.py index 4396ec151..a3c8f7928 100644 --- a/shapepipe/modules/find_exposures_package/find_exposures.py +++ b/shapepipe/modules/find_exposures_package/find_exposures.py @@ -25,7 +25,10 @@ class FindExposures(): Output file path w_log : logging.Logger Log file - + colnum: int + column number for exposure name in fits header + prefix: str + prefix for exposures """ def __init__(self, img_tile_path, output_path, w_log, colnum, prefix): From 805abdd436a64015aaff5d7e7412c31654f5d7d4 Mon Sep 17 00:00:00 2001 From: fabianhervaspeters Date: Tue, 18 Jul 2023 15:25:51 +0200 Subject: [PATCH 28/41] added docstring --- shapepipe/modules/find_exposures_package/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shapepipe/modules/find_exposures_package/__init__.py b/shapepipe/modules/find_exposures_package/__init__.py index 0b0debcc7..00653bf0b 100644 --- a/shapepipe/modules/find_exposures_package/__init__.py +++ b/shapepipe/modules/find_exposures_package/__init__.py @@ -28,6 +28,8 @@ COLNUM : int Column number to find exposure in fits header of tile image for the HISTORY string +EXP_PREFIX: str + Prefix of exposures """ __all__ = ['find_exposures.py'] From eaa32ade9aec82ce9390907417be2b1f863decc0 Mon Sep 17 00:00:00 2001 From: fabianhervaspeters Date: Tue, 18 Jul 2023 15:27:12 +0200 Subject: [PATCH 29/41] add space --- shapepipe/modules/mask_package/mask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapepipe/modules/mask_package/mask.py b/shapepipe/modules/mask_package/mask.py index fad3a0187..69a1c3c97 100644 --- a/shapepipe/modules/mask_package/mask.py +++ b/shapepipe/modules/mask_package/mask.py @@ -1179,7 +1179,7 @@ def _build_final_mask( ) external_flag.open() if final_mask is not None: - final_mask=final_mask.astype(np.int16, copy=False) + final_mask = final_mask.astype(np.int16, copy=False) final_mask += external_flag.get_data()[:, :] else: final_mask = external_flag.get_data()[:, :] From f0b36b49ace73b3f3921c153bea534ef68bd762d Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 18 Jul 2023 16:10:39 +0200 Subject: [PATCH 30/41] Added missing COLNUM to find exp config --- example/cfis/config_GitFeGie_symlink.ini | 1 + example/cfis/config_tile_Uz.ini | 2 +- shapepipe/modules/find_exposures_runner.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/cfis/config_GitFeGie_symlink.ini b/example/cfis/config_GitFeGie_symlink.ini index f3ab3499f..22e834533 100644 --- a/example/cfis/config_GitFeGie_symlink.ini +++ b/example/cfis/config_GitFeGie_symlink.ini @@ -98,6 +98,7 @@ FILE_EXT = .fits # NUMBERING_SCHEME (optional) string with numbering pattern for input files NUMBERING_SCHEME = -000-000 +COLNUM = 3 # Get exposures [GET_IMAGES_RUNNER_RUN_2] diff --git a/example/cfis/config_tile_Uz.ini b/example/cfis/config_tile_Uz.ini index aef899d0f..0bfe1a5cb 100644 --- a/example/cfis/config_tile_Uz.ini +++ b/example/cfis/config_tile_Uz.ini @@ -44,7 +44,7 @@ OUTPUT_DIR = $SP_RUN/output [JOB] # Batch size of parallel processing (optional), default is 1, i.e. run all jobs in serial -SMP_BATCH_SIZE = 1 +SMP_BATCH_SIZE = 16 # Timeout value (optional), default is None, i.e. no timeout limit applied TIMEOUT = 96:00:00 diff --git a/shapepipe/modules/find_exposures_runner.py b/shapepipe/modules/find_exposures_runner.py index 66a80f4f0..b72694c71 100644 --- a/shapepipe/modules/find_exposures_runner.py +++ b/shapepipe/modules/find_exposures_runner.py @@ -32,7 +32,7 @@ def find_exposures_runner( # Create output ascii file name output_path = f'{run_dirs["output"]}/exp_numbers{file_number_string}.txt' - # Give clumn number for exposure name in fits header + # Give column number for exposure name in fits header colnum = config.getint(module_config_sec, 'COLNUM') # Create find exposures class instance From 3d406961de6adda2ff5ecb47db19b206372a7fc6 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 5 Sep 2023 17:41:11 +0200 Subject: [PATCH 31/41] updated numpy version; job script with --n_smp option --- environment.yml | 1 + example/cfis/config_Pl_mccd.ini | 9 +++-- scripts/sh/job_sp.bash | 70 +++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/environment.yml b/environment.yml index 24f6dfd5f..bc8057326 100644 --- a/environment.yml +++ b/environment.yml @@ -4,6 +4,7 @@ channels: dependencies: - python=3.9 - pip>=21.2.4 + - numpy==1.21.6 - astropy==5.0 - automake==1.16.2 - autoconf==2.69 diff --git a/example/cfis/config_Pl_mccd.ini b/example/cfis/config_Pl_mccd.ini index 2739b8cde..a666d09dd 100644 --- a/example/cfis/config_Pl_mccd.ini +++ b/example/cfis/config_Pl_mccd.ini @@ -65,9 +65,12 @@ PLOT_MEANSHAPES = True X_GRID = 5 Y_GRID = 10 -# Optional: max values for elliptity and residual ellipticities -MAX_E = 0.05 -MAX_DE = 0.005 +# Optional: max values for focal plan plots (meanshape) +MAX_E = 0.1 +MAX_DE = 0.01 +MIN_R2 = 4.5 +MAX_R2 = 7 +MAX_DR2 = 0.03 PLOT_HISTOGRAMS = True REMOVE_OUTLIERS = False diff --git a/scripts/sh/job_sp.bash b/scripts/sh/job_sp.bash index b20abadd0..15cb1428a 100755 --- a/scripts/sh/job_sp.bash +++ b/scripts/sh/job_sp.bash @@ -11,6 +11,9 @@ # Date: v1.0 11/2020 # v1.1 01/2021 +# MKDEBUG TODO: +# Option to change SMP_BATCH_SIZE, not for MPI + # VM home, required for canfar run. ## On other machines set to $HOME @@ -28,6 +31,7 @@ psf='mccd' retrieve='vos' star_cat_for_mask='onthefly' results='cosmostat/kilbinger/results_v1' +n_smp=-1 nsh_step=-1 nsh_max=-1 nsh_jobs=8 @@ -56,9 +60,11 @@ usage="Usage: $(basename "$0") [OPTIONS] TILE_ID_1 [TILE_ID_2 [...]] \tdefault is '${star_cat_for_mask}'\n -o, --output_dir\n \toutput (upload) directory on vos:cfis, default='$results'\n + -n, --n_smp\n + \tnumber of jobs (SMP mode only), default from original config files\n + --nsh_step NSTEP\n --nsh_jobs NJOB\n \tnumber of shape measurement parallel jobs, default=$nsh_jobs\n - --nsh_step NSTEP\n \tnumber of objects per parallel shape module call, \n \tdefault: optimal number is computed\n --nsh_max NMAX\n @@ -106,6 +112,10 @@ while [ $# -gt 0 ]; do results="$2" shift ;; + -n|--n_smp) + n_smp="$2" + shift + ;; --nsh_max) nsh_max="$2" shift @@ -232,18 +242,27 @@ function command () { fi fi fi - - #return $res } # Run shapepipe command. If error occurs, upload sp log files before stopping script. -command_sp() { - cmd=$1 - str=$2 +function command_sp() { + local cmd=$1 + local str=$2 command "$1" "$2" } +# Set up config file and call shapepipe_run +function command_cfg_shapepipe() { + local config_name=$1 + local str=$2 + local _n_smp=$3 + + config_upd=$(set_config_n_smp $config_name $_n_smp) + local cmd="shapepipe_run -c $config_upd" + command_sp "$cmd" "$str" +} + # Tar and upload files to vos function upload() { base=$1 @@ -292,6 +311,35 @@ function print_env() { echo "***" } +function set_config_n_smp() { + local config_name=$1 + local _n_smp=$2 + + local config_orig="$SP_CONFIG/$config_name" + + if [[ $_n_smp != -1 ]]; then + # Update SMP batch size + local config_upd="$SP_CONFIG_MOD/$config_name" + update_config $config_orig $config_upd "SMP_BATCH_SIZE" $_n_smp + else + # Keep original config file + local config_upd=$config_orig + fi + + # Set "return" value (stdout) + echo "$config_upd" +} + +# Update config file +function update_config() { + local config_orig=$1 + local config_upd=$2 + local key=$3 + local val_upd=$4 + + cat $config_orig \ + | perl -ane 's/'$key'\s+=.+/'$key' = '$val_upd'/; print' > $config_upd +} ### Start ### @@ -303,6 +351,7 @@ echo "Processing $n_tile tile(s)" mkdir -p $SP_RUN cd $SP_RUN mkdir -p $OUTPUT +mkdir -p $SP_CONFIG_MOD # Processing @@ -347,19 +396,19 @@ fi if [[ $do_job != 0 ]]; then ### Uncompress tile weights - command_sp "shapepipe_run -c $SP_CONFIG/config_tile_Uz.ini" "Run shapepipe (uncompress tile weights)" + command_cfg_shapepipe "config_tile_Uz.ini" "Run shapepipe (uncompress tile weights)" $n_smp ### Split images into single-HDU files, merge headers for WCS info - command_sp "shapepipe_run -c $SP_CONFIG/config_exp_SpMh.ini" "Run shapepipe (split images, merge headers)" + command_cfg_shapepipe "config_exp_SpMh.ini" "Run shapepipe (split images, merge headers)" $n_smp fi -## Mask tiles and exposures: add star, halo, and Messier object masks (online) +## Mask tiles and exposures: add star, halo, and Messier object masks (online if "star_cat_for_mask" is "onthefly") (( do_job= $job & 4 )) if [[ $do_job != 0 ]]; then ### Mask tiles and exposures - command_sp "shapepipe_run -c $SP_CONFIG/config_MaMa_$star_cat_for_mask.ini" "Run shapepipe (mask)" + command_cfg_shapepipe "config_MaMa_$star_cat_for_mask.ini" "Run shapepipe (mask)" $n_smp fi @@ -392,7 +441,6 @@ fi if [[ $do_job != 0 ]]; then ### Prepare config files - mkdir -p $SP_CONFIG_MOD n_min=0 if [[ $nsh_step == -1 ]]; then n_obj=`get_number_objects.py` From 0c7da416e0e8b4883c25f08c20fb9bbbe4183b3f Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 5 Sep 2023 18:50:16 +0200 Subject: [PATCH 32/41] Included missing config options (plot limits) --- shapepipe/modules/mccd_plots_runner.py | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/shapepipe/modules/mccd_plots_runner.py b/shapepipe/modules/mccd_plots_runner.py index 615b2e11a..1c80505b7 100644 --- a/shapepipe/modules/mccd_plots_runner.py +++ b/shapepipe/modules/mccd_plots_runner.py @@ -70,6 +70,32 @@ def mccd_plots_runner( # Get parameters for meanshapes plots psf_model_type = config.get(module_config_sec, 'PSF') + + if config.has_option(module_config_sec, 'MAX_E'): + max_e = config.getfloat(module_config_sec, "MAX_E") + else: + max_e = None + + if config.has_option(module_config_sec, 'MAX_DE'): + max_de = config.getfloat(module_config_sec, "MAX_DE") + else: + max_de = None + + if config.has_option(module_config_sec, 'MIN_R2'): + min_r2 = config.getfloat(module_config_sec, "MIN_R2") + else: + min_r2 = None + + if config.has_option(module_config_sec, 'MAX_R2'): + max_r2 = config.getfloat(module_config_sec, "MAX_R2") + else: + max_r2 = None + + if config.has_option(module_config_sec, 'MAX_DR2'): + max_dr2 = config.getfloat(module_config_sec, "MAX_DR2") + else: + max_dr2 = None + x_nb_bins = config.getint(module_config_sec, 'X_GRID') y_nb_bins = config.getint(module_config_sec, 'Y_GRID') remove_outliers = config.getboolean(module_config_sec, 'REMOVE_OUTLIERS') @@ -107,6 +133,11 @@ def mccd_plots_runner( plot_meanshapes=plot_meanshapes, plot_histograms=plot_histograms, psf_model_type=psf_model_type, + max_e=max_e, + max_de=max_de, + min_r2=min_r2, + max_r2=max_r2, + max_dr2=max_dr2, ) else: msg = ( From a690f47d3a16a00542b6c332b8ebc54824c1c9d7 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 5 Sep 2023 18:51:11 +0200 Subject: [PATCH 33/41] Using plot limits for meanshape focal-plan plots --- .../mccd_package/mccd_plot_utilities.py | 72 +++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/shapepipe/modules/mccd_package/mccd_plot_utilities.py b/shapepipe/modules/mccd_package/mccd_plot_utilities.py index 972f73714..7096361c3 100644 --- a/shapepipe/modules/mccd_package/mccd_plot_utilities.py +++ b/shapepipe/modules/mccd_package/mccd_plot_utilities.py @@ -206,7 +206,12 @@ def plot_meanshapes( remove_outliers=False, plot_meanshapes=True, plot_histograms=True, - psf_model_type='mccd' + psf_model_type='mccd', + max_e=None, + max_de=None, + min_r2=None, + max_r2=None, + max_dr2=None, ): """Plot Mean Shapes. @@ -234,6 +239,21 @@ def plot_meanshapes( default is ``True`` psf_model_type : str, optional PSF model type, options are ``mccd`` or ``psfex``; defualt is ``mccd`` + max_e : float, optional + maximum value for focal plane ellipticity plots; default is ``None``, + set according to from data + max_de : float, optional + maximum value for focal plane residual ellipticity plots; default is + ``None``, set according to from data + min_r2 : float, optional + minimum value for focal plane size plots, default is ``None``; set + according to data + max_r2 : float, optional + maximum value for focal plane size plots, default is ``None``; set + according to data + max_dr2 : float, optional + maximum value for focal plane residual size plots, default is ``None``; + set according to data """ # READ FULL STARCAT @@ -378,8 +398,13 @@ def plot_meanshapes( if plot_meanshapes: # e_1 - vmax = max(np.nanmax(ccd_maps[:, :, 0]), - np.abs(np.nanmin(ccd_maps[:, :, 0]))) + if max_e: + vmax = max_e + else: + vmax = max( + np.nanmax(ccd_maps[:, :, 0]), + np.abs(np.nanmin(ccd_maps[:, :, 0])) + ) vmin = -vmax wind = [vmin, vmax] title = ( @@ -410,7 +435,10 @@ def plot_meanshapes( e1_res = e1_res[~np.isnan(e1_res)] rmse_e1 = np.sqrt(np.mean(e1_res ** 2)) w_log.info(f'Bins: e1 residual RMSE: {rmse_e1:.6f}\n') - vmax = np.nanmax(abs(ccd_maps[:, 0, 0] - ccd_maps[:, 1, 0])) + if max_de: + vmax = max_de + else: + vmax = np.nanmax(abs(ccd_maps[:, 0, 0] - ccd_maps[:, 1, 0])) vmin = -vmax wind = [vmin, vmax] title = ( @@ -426,10 +454,13 @@ def plot_meanshapes( ) # e_2 - vmax = max( - np.nanmax(ccd_maps[:, :, 1]), - np.abs(np.nanmin(ccd_maps[:, :, 1])) - ) + if max_e: + vmax = max_e + else: + vmax = max( + np.nanmax(ccd_maps[:, :, 1]), + np.abs(np.nanmin(ccd_maps[:, :, 1])) + ) vmin = -vmax wind = [vmin, vmax] title = ( @@ -461,7 +492,10 @@ def plot_meanshapes( e2_res = e2_res[~np.isnan(e2_res)] rmse_e2 = np.sqrt(np.mean(e2_res ** 2)) w_log.info(f'Bins: e2 residual RMSE: {rmse_e2:.6f}\n') - vmax = np.nanmax(abs(ccd_maps[:, 0, 1] - ccd_maps[:, 1, 1])) + if max_de: + vmax = max_de + else: + vmax = np.nanmax(abs(ccd_maps[:, 0, 1] - ccd_maps[:, 1, 1])) vmin = -vmax wind = [vmin, vmax] title = ( @@ -477,7 +511,15 @@ def plot_meanshapes( ) # R^2 - wind = [0, np.nanmax(ccd_maps[:, :, 2])] + if min_r2: + vmin = min_r2 + else: + vmin = 0 + if max_r2: + vmax = max_r2 + else: + vmax = nanmax(ccd_maps[:, :, 2]) + wind = [vmin, vmax] colorbar_ampl = 1 title = ( f'R_2 (stars), std={np.nanstd(ccd_maps[:, 0, 2]):.5e}\n' @@ -514,8 +556,14 @@ def plot_meanshapes( R2_res = R2_res[~np.isnan(R2_res)] rmse_r2 = np.sqrt(np.mean(R2_res ** 2)) w_log.info(f"Bins: R2 residual RMSE: {rmse_r2:.6f}\n") - vmax = np.nanmax( - abs((ccd_maps[:, 0, 2] - ccd_maps[:, 1, 2]) / ccd_maps[:, 0, 2])) + if max_dr2: + vmax = max_dr2 + else: + vmax = np.nanmax( + abs( + (ccd_maps[:, 0, 2] - ccd_maps[:, 1, 2]) / ccd_maps[:, 0, 2] + ) + ) wind = [0, vmax] std_title = np.nanstd( (ccd_maps[:, 0, 2] - ccd_maps[:, 1, 2]) / ccd_maps[:, 0, 2] From 21dfd7b273b6f43f3367486e4eb28c8a50c1fbe2 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 5 Sep 2023 19:02:25 +0200 Subject: [PATCH 34/41] replaced hard-coded transformation sigma to fhwm --- shapepipe/modules/make_cat_package/make_cat.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shapepipe/modules/make_cat_package/make_cat.py b/shapepipe/modules/make_cat_package/make_cat.py index 46203dac2..6bbe26648 100644 --- a/shapepipe/modules/make_cat_package/make_cat.py +++ b/shapepipe/modules/make_cat_package/make_cat.py @@ -16,6 +16,7 @@ from sqlitedict import SqliteDict from shapepipe.pipeline import file_io +from shapepipe.utitities import galaxy def prepare_final_cat_file(output_path, file_number_string): @@ -556,7 +557,9 @@ def _save_psf_data(self, galaxy_psf_path): ) self._add2dict(f'PSF_ELL_{epoch + 1}', e_psf, idx) - psf_fwhm = gpc_data['SHAPES']['SIGMA_PSF_HSM'] * 2.355 + psf_fwhm = galaxy.sigma_to_fwhm( + gpc_data['SHAPES']['SIGMA_PSF_HSM'] + ) self._add2dict(f'PSF_FWHM_{epoch + 1}', psf_fwhm, idx) flag_psf = gpc_data['SHAPES']['FLAG_PSF_HSM'] From b45bf697c4a178308f841da357970b966d61d56d Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Tue, 5 Sep 2023 19:18:00 +0200 Subject: [PATCH 35/41] Removed unused config entry for mccd_plot_runner --- example/cfis/config_tile_Sx_exp_mccd.ini | 7 ------- 1 file changed, 7 deletions(-) diff --git a/example/cfis/config_tile_Sx_exp_mccd.ini b/example/cfis/config_tile_Sx_exp_mccd.ini index 66e041e10..c195a8c80 100644 --- a/example/cfis/config_tile_Sx_exp_mccd.ini +++ b/example/cfis/config_tile_Sx_exp_mccd.ini @@ -253,13 +253,6 @@ NUMBERING_SCHEME = -0000000 [MCCD_PLOTS_RUNNER] -# Path to MCCD config file -CONFIG_PATH = $SP_CONFIG/config_MCCD.ini - -MODE = FIT_VALIDATION - -VERBOSE = False - # Now MCCD has created a focal-plane PSF model, including all CCDS per images, # thus single-exposure files NUMBERING_SCHEME = -0000000 From 0103694b7fbecb4aa7742830e1b92a50ad109b65 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 6 Sep 2023 10:27:42 +0200 Subject: [PATCH 36/41] Outsource vos commands to cs_util (#606) * removed shapepipe/utilities/canfar.py, moved to cs_util (0.0.4) * removed unused imports * modif to mccd config file (run_datetime) * env yml: cs_util is pip, not conda package * Update environment.yml Co-authored-by: Samuel Farrens --------- Co-authored-by: Samuel Farrens --- environment.yml | 1 + example/cfis/config_MsPl_mccd.ini | 2 +- scripts/python/canfar_avail_results.py | 2 +- .../modules/get_images_package/get_images.py | 2 +- shapepipe/utilities/__init__.py | 2 +- shapepipe/utilities/canfar.py | 190 ------------------ shapepipe/utilities/cfis.py | 2 - 7 files changed, 5 insertions(+), 196 deletions(-) delete mode 100644 shapepipe/utilities/canfar.py diff --git a/environment.yml b/environment.yml index bc8057326..9279402ef 100644 --- a/environment.yml +++ b/environment.yml @@ -16,6 +16,7 @@ dependencies: - numba==0.54.1 - pandas==1.4.1 - pip: + - cs_util==0.0.5 - mccd==1.2.3 - modopt==1.6.0 - PyQt5==5.15.6 diff --git a/example/cfis/config_MsPl_mccd.ini b/example/cfis/config_MsPl_mccd.ini index ef8698e0f..5a2cc42c6 100644 --- a/example/cfis/config_MsPl_mccd.ini +++ b/example/cfis/config_MsPl_mccd.ini @@ -13,7 +13,7 @@ VERBOSE = True RUN_NAME = run_sp_MsPl # Add date and time to RUN_NAME, optional, default: False -RUN_DATETIME = False +RUN_DATETIME = True ## ShapePipe execution options diff --git a/scripts/python/canfar_avail_results.py b/scripts/python/canfar_avail_results.py index bc062d808..c44c90e31 100755 --- a/scripts/python/canfar_avail_results.py +++ b/scripts/python/canfar_avail_results.py @@ -19,7 +19,7 @@ from optparse import OptionParser -from shapepipe.utilities.canfar import dir_list +from cs_util.canfar import dir_list from shapepipe.utilities import cfis diff --git a/shapepipe/modules/get_images_package/get_images.py b/shapepipe/modules/get_images_package/get_images.py index 9004e23cf..d465d0719 100644 --- a/shapepipe/modules/get_images_package/get_images.py +++ b/shapepipe/modules/get_images_package/get_images.py @@ -12,7 +12,7 @@ import sys from shapepipe.modules.module_decorator import module_runner -from shapepipe.utilities.canfar import vosHandler +from cs_util.canfar import vosHandler # pragma: no cover diff --git a/shapepipe/utilities/__init__.py b/shapepipe/utilities/__init__.py index 2c27cd7df..63b425136 100644 --- a/shapepipe/utilities/__init__.py +++ b/shapepipe/utilities/__init__.py @@ -7,4 +7,4 @@ """ -__all__ = ['canfar', 'file_system', 'cfis', 'galaxy'] +__all__ = ['file_system', 'cfis', 'galaxy'] diff --git a/shapepipe/utilities/canfar.py b/shapepipe/utilities/canfar.py deleted file mode 100644 index bf67c8574..000000000 --- a/shapepipe/utilities/canfar.py +++ /dev/null @@ -1,190 +0,0 @@ -"""CANFAR TOOLS. - -This module defines methods for managing CANFAR specific actions. - -:Author: Samuel Farrens - Martin Kilbinger - -""" - -import os -import sys -from contextlib import redirect_stdout -from io import StringIO - -try: - import vos.commands as vosc -except ImportError: # pragma: no cover - import_fail = True -else: - import_fail = False - - -class vosError(Exception): - """VOS Error. - - Generic error that is raised by the vosHandler. - - """ - - pass - - -class vosHandler: - """VOS Handler. - - This class manages the use of VOS commands. - - Parameters - ---------- - command : str - VOS command name - - """ - - def __init__(self, command): - - self._check_vos_install() - self._avail_commands = tuple(vosc.__all__) - self.command = command - - @staticmethod - def _check_vos_install(): - """Check VOS Install. - - Check if VOS is correctly installed. - - Raises - ------ - ImportError - if vos package cannot be imported - - """ - if import_fail: - raise ImportError( - 'vos package not found, re-install ShapePipe ' - + 'with \'./install_shapepipe --vos\'' - ) - - @property - def command(self): - """Set Command. - - This method sets the VOS command property. - - Raises - ------ - ValueError - if value is not valid vos command - - """ - return self._command - - @command.setter - def command(self, value): - - if value not in self._avail_commands: - raise ValueError( - f'vos command must be one of {self._avail_commands}' - ) - - self._command = getattr(vosc, value) - - def __call__(self, *args, **kwargs): - """Call Method. - - This method allows class instances to be called as functions. - - Raises - ------ - vosError - if error in vos command occurs - - """ - try: - self._command() - - except Exception: - raise vosError( - f'Error in VOs command: {self._command.__name__}' - ) - - -def download(source, target, verbose=False): - """Download. - - Download file from vos. - - Parameters - ---------- - source : str - source path on vos - target : str - target path - verbose : bool, optional, default=False - verbose output if True - - Returns - ------- - status : bool - status, True/False or success/failure - - """ - cmd = 'vcp' - - if not os.path.exists(target): - sys.argv = [cmd, source, target] - if verbose: - print(f'Downloading file {source} to {target}...') - vcp = vosHandler(cmd) - - vcp() - if verbose: - print('Download finished.') - else: - if verbose: - print(f'Target file {target} exists, skipping download.') - - -def dir_list(path, verbose=False): - """Set Directory List. - - List content of path on vos. - - Parameters - ---------- - path : str - path on vos, starts with 'vos:cfis/...' - verbose : bool, optional, default=False - verbose output if True - - Raises - ------ - HTTPError, KeyError - if error occurs during vos command - - Returns - ------- - vls_out : array of str - file or directory at path - - """ - cmd = 'vls' - sys.argv = [cmd, path] - vls = vosHandler(cmd) - - if verbose: - print('Getting vos directory content from vls...') - - f = StringIO() - - try: - with redirect_stdout(f): - vls() - except Exception: - print('Error during vls command') - raise - - vls_out = f.getvalue() - - return vls_out.split('\n') diff --git a/shapepipe/utilities/cfis.py b/shapepipe/utilities/cfis.py index 9c9da9bcf..c8cdcb7a5 100644 --- a/shapepipe/utilities/cfis.py +++ b/shapepipe/utilities/cfis.py @@ -14,9 +14,7 @@ import astropy.coordinates as coords import numpy as np import pylab as plt -from astropy import units from astropy.io import ascii -from astropy.wcs import WCS from shapepipe.utilities.file_system import mkdir From 400eb12be39ea172dca0eb3a6de1a24ff9f601dd Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 6 Sep 2023 10:50:34 +0200 Subject: [PATCH 37/41] Removed faulty line in merge final cat script (#647) --- scripts/python/merge_final_cat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/python/merge_final_cat.py b/scripts/python/merge_final_cat.py index ed79b27ee..1a160c449 100755 --- a/scripts/python/merge_final_cat.py +++ b/scripts/python/merge_final_cat.py @@ -316,7 +316,6 @@ def main(argv=None): add_this_l = False # mark to add if correct extension, matches input pattern, - not `.npy` file if ( this_l.endswith(ext) and (f'{param.input_name_base}' in this_l) From 11347567d2813073193cec53dcd5296807d4a496 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Wed, 6 Sep 2023 13:11:57 +0200 Subject: [PATCH 38/41] N epoch test (#627) * Added key check and error to multi-epoch mccd interpolation * . * More detail in error msg, see PR review --- .../mccd_package/mccd_interpolation_script.py | 14 +++++++++++++- .../modules/psfex_interp_package/psfex_interp.py | 14 +++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/shapepipe/modules/mccd_package/mccd_interpolation_script.py b/shapepipe/modules/mccd_package/mccd_interpolation_script.py index 342e20a35..40e644e8b 100644 --- a/shapepipe/modules/mccd_package/mccd_interpolation_script.py +++ b/shapepipe/modules/mccd_package/mccd_interpolation_script.py @@ -378,6 +378,11 @@ def _interpolate_me(self): Interpolate PSFs for multi-epoch run. + Raises + ------ + KeyError + If 'N_EPOCH' key not in input catalogue + Returns ------- output_dict: dict @@ -389,7 +394,14 @@ def _interpolate_me(self): cat.open() all_id = np.copy(cat.get_data()['NUMBER']) - n_epoch = np.copy(cat.get_data()['N_EPOCH']) + key_ne = 'N_EPOCH' + if key_ne not in cat.get_data(): + raise KeyError( + f'Key {key_ne} not found in input galaxy catalogue, needed for' + + ' PSF interpolation to multi-epoch data; run previous module' + + ' (SExtractor) in multi-epoch mode' + ) + n_epoch = np.copy(cat.get_data()[key_ne]) list_ext_name = cat.get_ext_name() hdu_ind = [i for i in range(len(list_ext_name)) if diff --git a/shapepipe/modules/psfex_interp_package/psfex_interp.py b/shapepipe/modules/psfex_interp_package/psfex_interp.py index 767c43b1b..3ac1b25ea 100644 --- a/shapepipe/modules/psfex_interp_package/psfex_interp.py +++ b/shapepipe/modules/psfex_interp_package/psfex_interp.py @@ -551,6 +551,11 @@ def _interpolate_me(self): Interpolate PSFs for multi-epoch run. + Raises + ------ + KeyError + If 'N_EPOCH' key not in input catalogue + Returns ------- dict @@ -562,7 +567,14 @@ def _interpolate_me(self): cat.open() all_id = np.copy(cat.get_data()['NUMBER']) - n_epoch = np.copy(cat.get_data()['N_EPOCH']) + key_ne = 'N_EPOCH' + if key_ne not in cat.get_data(): + raise KeyError( + f'Key {key_ne} not found in input galaxy catalogue, needed for' + + ' PSF interpolation to multi-epoch data; run previous module' + + ' (SExtractor) in multi-epoch mode' + ) + n_epoch = np.copy(cat.get_data()[key_me]) list_ext_name = cat.get_ext_name() hdu_ind = [ From a75514a7aa1944e3a25cab7a5ab83c43cc9522f8 Mon Sep 17 00:00:00 2001 From: Martin Kilbinger Date: Fri, 8 Sep 2023 14:51:37 +0200 Subject: [PATCH 39/41] mccd focal-plane plots: fixed coordinate flips for psfex --- example/cfis/config_Pl_psfex.ini | 7 +++++-- shapepipe/modules/mccd_package/mccd_plot_utilities.py | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/example/cfis/config_Pl_psfex.ini b/example/cfis/config_Pl_psfex.ini index bf1a062c1..c561f15a5 100644 --- a/example/cfis/config_Pl_psfex.ini +++ b/example/cfis/config_Pl_psfex.ini @@ -66,8 +66,11 @@ X_GRID = 5 Y_GRID = 10 # Optional: max values for elliptity and residual ellipticities -MAX_E = 0.05 -MAX_DE = 0.005 +MAX_E = 0.1 +MAX_DE = 0.01 +MIN_R2 = 4.5 +MAX_R2 = 7 +MAX_DR2 = 0.03 PLOT_HISTOGRAMS = True REMOVE_OUTLIERS = False diff --git a/shapepipe/modules/mccd_package/mccd_plot_utilities.py b/shapepipe/modules/mccd_package/mccd_plot_utilities.py index 7096361c3..1d3eb9f14 100644 --- a/shapepipe/modules/mccd_package/mccd_plot_utilities.py +++ b/shapepipe/modules/mccd_package/mccd_plot_utilities.py @@ -377,13 +377,17 @@ def plot_meanshapes( xs_loc, ys_loc = all_X[ccd_mask] - x_shift, all_Y[ccd_mask] - y_shift - # swap axes to match CCD orientation and origin convention - ys_loc = loc2glob.y_npix - ys_loc + 1 + if psf_model_type == 'mccd': + # swap axes to match CCD orientation and origin convention + ys_loc = loc2glob.y_npix - ys_loc + 1 # digitalize into bins xbins = np.digitize(xs_loc, grid[0]) ybins = np.digitize(ys_loc, grid[1]) + if psf_model_type == 'psfex': + xbins, ybins = megacam_flip(xbins, ybins, ccd_nb, nb_pixel) + for xb in range(nb_pixel[0]): for yb in range(nb_pixel[1]): bin_star_shapes = star_shapes[ @@ -518,7 +522,7 @@ def plot_meanshapes( if max_r2: vmax = max_r2 else: - vmax = nanmax(ccd_maps[:, :, 2]) + vmax = np.nanmax(ccd_maps[:, :, 2]) wind = [vmin, vmax] colorbar_ampl = 1 title = ( From 3201d32e48fd4495434fdcb8e27c4205e54f6bc7 Mon Sep 17 00:00:00 2001 From: fabianhervaspeters <87416002+fabianhervaspeters@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:59:46 +0100 Subject: [PATCH 40/41] Update file_io.py np.str gave attribute error, deprecated --- shapepipe/pipeline/file_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapepipe/pipeline/file_io.py b/shapepipe/pipeline/file_io.py index a768f0c06..52e847147 100644 --- a/shapepipe/pipeline/file_io.py +++ b/shapepipe/pipeline/file_io.py @@ -1549,7 +1549,7 @@ def _get_fits_col_type(self, col_data): col_type = 'D' elif type(col_data[0]) is bool: col_type = 'L' - elif type(col_data[0]) in [str, np.str, np.str_, np.str0]: + elif type(col_data[0]) in [str, np.str_, np.str0]: col_type = 'A' else: col_type = 'D' From f789b762fc682de7651b7f59596794c0bdf6953d Mon Sep 17 00:00:00 2001 From: fabianhervaspeters <87416002+fabianhervaspeters@users.noreply.github.com> Date: Mon, 20 May 2024 19:28:46 +0200 Subject: [PATCH 41/41] make_cat.py typo small typo utilities --- shapepipe/modules/make_cat_package/make_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shapepipe/modules/make_cat_package/make_cat.py b/shapepipe/modules/make_cat_package/make_cat.py index 6bbe26648..4e30e3552 100644 --- a/shapepipe/modules/make_cat_package/make_cat.py +++ b/shapepipe/modules/make_cat_package/make_cat.py @@ -16,7 +16,7 @@ from sqlitedict import SqliteDict from shapepipe.pipeline import file_io -from shapepipe.utitities import galaxy +from shapepipe.utilities import galaxy def prepare_final_cat_file(output_path, file_number_string):