en:praktikum:photometrie_python

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:praktikum:photometrie_python [2026/04/22 12:09] – [Cross correlation with the extracted data] rhainichen:praktikum:photometrie_python [2026/09/09 09:04] (current) – [World Coordinate System] rhainich
Line 1: Line 1:
 +====== PlayGround ======
 +
 ====== N2 - Photometry of open star clusters ====== ====== N2 - Photometry of open star clusters ======
  
Line 19: Line 21:
 ===== Observation ===== ===== Observation =====
  
-Night observations at the OST of the University of Potsdam (alternatively also at the 70cm telescope of the AIP) are required. Please refer to the checklist for night observations for preparation. +Night observations at the OST of the University of Potsdam (alternatively also at the 70cm telescope of the AIP) are required. Please refer to the checklist for night observations for preparation.
  
-For the data reduction, flatfields and darks must be taken in addition to the actual images of the star clusters. Bias images (with zero exposure time) are not necessary, if for each set of star cluster images and flatfields also darks with the same exposure times are taken. At the OST, the flatfields can be taken with a flat field panel after observing the star clusters. If observing at the AIP, it is recommended to take the flatfields already at dusk (or against a white evenly illuminated wall). In this case, bias images are also required and should be taken with the cover closed. In any case, in absolute darkness and with the covers closed, the dark frames should be acquired. To minimize noise, each set of darks and flats should consist of at least 30 individual exposures. +For the data reduction, flatfields and darks must be taken in addition to the actual images of the star clusters. Bias images (with zero exposure time) are not necessary, if for each set of star cluster images and flatfields also darks with the same exposure times are taken. At the OST, the flatfields can be taken with a flat field panel after observing the star clusters. If observing at the AIP, it is recommended to take the flatfields already at dusk (or against a white evenly illuminated wall). In this case, bias images are also required and should be taken with the cover closed. In any case, in absolute darkness and with the covers closed, the dark frames should be acquired. To minimize noise, each set of darks and flats should consist of at least 30 individual exposures.
  
-After darkness has fallen, the images of the star clusters are taken. To get a sufficient number of counts also from fainter stars, the exposures should be long enough. Depending on the camera and the observed object the time span for single images can be between 20 seconds and several minutes. Especially if brighter objects are in the field of view or if the accuracy of the tracking is insufficient, it is useful to take several exposures and add them up later. With the typical seeing in Potsdam, the currently used cameras can be operated with 2x2-[[en:ost:ccds:ccdops#Binning|Binning]] or 3x3-[[en:ost:ccds:ccdops#Binning|Binning]] to further increase the signal to noise ratio. In any case, a total exposure time of at least 40 minutes should be achieved per filter. +After darkness has fallen, the images of the star clusters are taken. To get a sufficient number of counts also from fainter stars, the exposures should be long enough. Depending on the camera and the observed object the time span for single images can be between 20 seconds and several minutes. Especially if brighter objects are in the field of view or if the accuracy of the tracking is insufficient, it is useful to take several exposures and add them up later. With the typical seeing in Potsdam, the currently used cameras can be operated with 2x2-[[en:ost:ccds:ccdops#Binning|Binning]] or 3x3-[[en:ost:ccds:ccdops#Binning|Binning]] to further increase the signal to noise ratio. In any case, a total exposure time of at least 40 minutes should be achieved per filter.
  
 ===== Data reduction ===== ===== Data reduction =====
Line 32: Line 34:
  
 The first thing to do is to log in to the [[en:praktikum:zugang| laboratory computer]]. The next step is to copy the observation data (FIT files), including flatfield and bias/darkframe images from the directory ''~/data/<date>'' to your own directory ''~/data_reduction/''. There are several tools to view the two-dimensional CCD images (data arrays) stored in the FIT format. For example by means of //ds9//: The first thing to do is to log in to the [[en:praktikum:zugang| laboratory computer]]. The next step is to copy the observation data (FIT files), including flatfield and bias/darkframe images from the directory ''~/data/<date>'' to your own directory ''~/data_reduction/''. There are several tools to view the two-dimensional CCD images (data arrays) stored in the FIT format. For example by means of //ds9//:
-   ds9 filename.fit +   ds9 filename.fit
 opens the image ''filename.fit'' with //ds9//. After opening an image, you can vary the brightness and contrast by moving the cursor while holding down the right mouse button. Further options (zoom, false color display, rotate, opens the image ''filename.fit'' with //ds9//. After opening an image, you can vary the brightness and contrast by moving the cursor while holding down the right mouse button. Further options (zoom, false color display, rotate,
 mirroring etc.) can be accessed via buttons. The coordinates of the current cursor position are displayed in the upper left corner. It is also possible to open several images at once (buttons ''Frame'' -> ''new frame'', then open another file with ''File'' -> ''open''). With the blink option (buttons: ''Frame'' -> ''blink'') one can compare several images easily. mirroring etc.) can be accessed via buttons. The coordinates of the current cursor position are displayed in the upper left corner. It is also possible to open several images at once (buttons ''Frame'' -> ''new frame'', then open another file with ''File'' -> ''open''). With the blink option (buttons: ''Frame'' -> ''blink'') one can compare several images easily.
  
-Alternatively, all images can be opened at the same time. For this purpose +Alternatively, all images can be opened at the same time. For this purpose
    ds9 *.fit    ds9 *.fit
 (but this is not suitable for a large number of files). In //ds9// the frames can be viewed as above or each frame can be viewed individually one after the other (button ''Frame'' -> ''Single Frame''). You can switch between the frames by pressing the tab key. (but this is not suitable for a large number of files). In //ds9// the frames can be viewed as above or each frame can be viewed individually one after the other (button ''Frame'' -> ''Single Frame''). You can switch between the frames by pressing the tab key.
-   +
 The **usable** frames are to be selected for further processing. For example, the stars should be seen as round discs. Images with oval-shaped stars are not to be used. The **usable** frames are to be selected for further processing. For example, the stars should be seen as round discs. Images with oval-shaped stars are not to be used.
  
Line 54: Line 56:
 If you want to reconnect, you can do so by typing If you want to reconnect, you can do so by typing
  
-   workon ost_photometry +   workon ost_photometry
  
-This is also necessary if you reconnect to columba, e.g. after a break, and want to continue the data analysis. +This is also necessary if you reconnect to columba, e.g. after a break, and want to continue the data analysis.
  
 The OST photometry pipeline can then be installed in the terminal using //pip// as follows The OST photometry pipeline can then be installed in the terminal using //pip// as follows
Line 62: Line 64:
    pip install ost_photometry    pip install ost_photometry
  
-All necessary dependencies are also installed in this way. +All necessary dependencies are also installed in this way.
  
 ==== Reduction pipeline: darkframes, flatfields, and image stacking ==== ==== Reduction pipeline: darkframes, flatfields, and image stacking ====
Line 69: Line 71:
  
 Copy the //Python// script ''1_add_images.py'' from the directory ''~/scripts/n2/'' into your local working directory. After that you should open it with a text editor of your choice to adjust the paths for the images. To be able to read and verify a larger amount of images, the program expects a separation of the data into different subdirectories (variables: ''bias'', ''darks'', ''flats'', ''images''). There should be one directory each for the images of the star cluster, the flatfields, and the dark frames. A possible directory structure could be: Copy the //Python// script ''1_add_images.py'' from the directory ''~/scripts/n2/'' into your local working directory. After that you should open it with a text editor of your choice to adjust the paths for the images. To be able to read and verify a larger amount of images, the program expects a separation of the data into different subdirectories (variables: ''bias'', ''darks'', ''flats'', ''images''). There should be one directory each for the images of the star cluster, the flatfields, and the dark frames. A possible directory structure could be:
-  +
   /bias/   /bias/
   /darks/   /darks/
   /flats/   /flats/
   /images/   /images/
-   + 
-The //Python// script automatically detects the filters and exposure times used. Based on this, it arranges and classifies the files automatically without any further interaction. If you are sure that all ''FIT-Header'' keywords are set correctly, you can try to put all files into one directory. In this case only the path ''rawfiles'' must be set in the script. Otherwise, the paths to the subfolders for the flats, darks, etc. must be specified. Hence either ''bias'', ''darks'', ''flats'', and ''images'' musst be specified or only ''raw_files''. +The //Python// script automatically detects the filters and exposure times used. Based on this, it arranges and classifies the files automatically without any further interaction. If you are sure that all ''FIT-Header'' keywords are set correctly, you can try to put all files into one directory. In this case only the path ''rawfiles'' must be set in the script. Otherwise, the paths to the subfolders for the flats, darks, etc. must be specified. Hence either ''bias'', ''darks'', ''flats'', and ''images'' musst be specified or only ''raw_files''.
  
 /* /*
Line 103: Line 105:
 Once the path information and the name of the star cluster have been specified, the script can be executed with Once the path information and the name of the star cluster have been specified, the script can be executed with
  
-   python 1_add_images.py       +   python 1_add_images.py 
-  +
 The results are saved in a new subdirectory called ''output''. The results are saved in a new subdirectory called ''output''.
  
Line 118: Line 120:
  
 <code Python> <code Python>
-import os 
- 
 import numpy as np import numpy as np
  
Line 128: Line 128:
 from astroquery.vizier import Vizier from astroquery.vizier import Vizier
  
-from ost_photometry import checks 
 from ost_photometry.analyze.extraction import main_extract from ost_photometry.analyze.extraction import main_extract
 +from ost_photometry.output_layout import diagnostics_dir
 from ost_photometry.analyze.plots import ( from ost_photometry.analyze.plots import (
 +    calibrated_color,
 +    catalog_fit_residual,
     plot_calibration_color_color_cal_stars,     plot_calibration_color_color_cal_stars,
     plot_combined_separation_histograms,     plot_combined_separation_histograms,
Line 141: Line 143:
 ) )
 from ost_photometry.utilities import ( from ost_photometry.utilities import (
-    find_wcs_astrometry,+    find_wcs_astap,
     Image,     Image,
 ) )
Line 153: Line 155:
 warnings.filterwarnings('ignore') warnings.filterwarnings('ignore')
 </code> </code>
-                                             +
 The last two lines disable some warnings that unnecessarily clutter the console output. The last two lines disable some warnings that unnecessarily clutter the console output.
 ==== Defining some variables ==== ==== Defining some variables ====
  
-Next, some variables should be defined. These should be at least the name of the cluster (''name''), the directory where the results should be stored (''out_path'') and the paths (''V_path'' and ''B_path'') to the two images of the cluster in the considered filters (here ''V'' and ''B'') obtained from the [[en:praktikum:photometrie_python#data_reduction|reduction pipeline]]. +Next, some variables should be defined. These should be at least the name of the cluster (''name''), the directory where the results should be stored (''out_path'') and the paths (''V_path'' and ''B_path'') to the two images of the cluster in the considered filters (here ''V'' and ''B'') obtained from the [[en:praktikum:photometrie_python#data_reduction|reduction pipeline]].
  
 <code Python> <code Python>
Line 171: Line 173:
 </code> </code>
  
-Note: The variable names given here and in the following are only examples and can be replaced by any other name.  +Note: The variable names given here and in the following are only examples and can be replaced by any other name.
  
 Note: If the images are not in a subdirectory of the current directory, the path can also refer to the next higher level by using ''../''. Note: If the images are not in a subdirectory of the current directory, the path can also refer to the next higher level by using ''../''.
Line 177: Line 179:
 ==== Reading in the images ==== ==== Reading in the images ====
  
-We open the FIT files with image data by means of the ''image'' function provided by the OST library. This has the advantage that we do not have to worry about the details of the read-in process, and at the same time we have a //Python// object for each image, which we can use to store some of the results obtained in the following steps. The ''image'' function has the following arguments: 1. index of the image (can be set to ''0''), 2. filter name, 3. path to the image file and 4. path to the output directory: +We open the FIT files with image data by means of the ''image'' function provided by the OST library. This has the advantage that we do not have to worry about the details of the read-in process, and at the same time we have a //Python// object for each image, which we can use to store some of the results obtained in the following steps. The ''image'' function has the following arguments: 1. index of the image (can be set to ''0''), 2. filter name, 3. path to the image file and 4. path to the output directory:
  
 <code Python> <code Python>
Line 187: Line 189:
 ==== World Coordinate System ==== ==== World Coordinate System ====
  
-The images created by the OST are usually delivered without a so-called WCS. WCS stands for World Coordinate System and allows to assign sky coordinates to each pixel in the image. In //ds9// these coordinates will be displayed in the coordinates window of //ds9// when pointing with the mouse pointer on certain pixels or objects. This is very helpful if you want to compare the positions of stars in your own image with those in star catalogs. This could be quite helpful for the calibration of the stellar magnitudes later on ;-).  +The images created by the OST are usually delivered without a so-called WCS. WCS stands for World Coordinate System and allows to assign sky coordinates to each pixel in the image. In //ds9// these coordinates will be displayed in the coordinates window of //ds9// when pointing with the mouse pointer on certain pixels or objects. This is very helpful if you want to compare the positions of stars in your own image with those in star catalogs. This could be quite helpful for the calibration of the stellar magnitudes later on ;-).
  
 /* /*
Line 198: Line 200:
 </code> </code>
  
-The FOV information will be automatically stored in the ''image'' object. +The FOV information will be automatically stored in the ''image'' object.
  
-Afterwards, we +Afterwards, we
 */ */
  
-We will use the function ''find_wcs_astrometry'' to determine the WCS:+We will use the function ''find_wcs_astap'' to determine the WCS:
  
 <code Python> <code Python>
 #   Find the WCS solution for the images #   Find the WCS solution for the images
-find_wcs_astrometry(V_image) +find_wcs_astap(V_image) 
-find_wcs_astrometry(B_image)+find_wcs_astap(B_image)
 </code> </code>
  
-When a WCS solution is found, +When a WCS solution is found,
  
     WCS solution found :)     WCS solution found :)
- +
 is printed in green on the command line. is printed in green on the command line.
 +
 ==== Localization of the stars ==== ==== Localization of the stars ====
  
 === Finding the stars === === Finding the stars ===
  
-The identification of the stars in the two images is performed using the ''main_extract'' function. This function takes as the first argument the ''image'' object. As an optional argument, the extraction method can be selected (''photometry''). Here we specify '''APER''', and thus select aperture photometry, where the flux of the individual objects and the associated sky backgrounds is read out within fixed apertures (here circular and ring-shaped, respectively). To specify these apertures, we have to give a radius for the circular object aperture (''rstars'') and two radii for the annular background aperture (''rbg_in'' and ''rbg_out''). In previous observations, the respective values were ''4'', ''7'', and ''10'', respectively. The radii are in arc seconds. +The identification of the stars in the two images is performed using the ''main_extract'' function. This function takes as the first argument the ''image'' object. As an optional argument, the extraction method can be selected (''photometry''). Here we specify '''APER''', and thus select aperture photometry, where the flux of the individual objects and the associated sky backgrounds is read out within fixed apertures (here circular and ring-shaped, respectively). To specify these apertures, we have to give a radius for the circular object aperture (''rstars'') and two radii for the annular background aperture (''rbg_in'' and ''rbg_out''). In previous observations, the respective values were ''4'', ''7'', and ''10'', respectively. The radii are in arc seconds.
  
 <code Python> <code Python>
Line 241: Line 244:
  
 In addition to the star coordinates (in pixels), ''main_extract'' also automatically stores all extracted fluxes in the ''image'' objects. In addition to the star coordinates (in pixels), ''main_extract'' also automatically stores all extracted fluxes in the ''image'' objects.
 +
 === Check identified stars === === Check identified stars ===
  
 The function ''main_extract'' has the nice feature that it marks the identified stars on a so called "starmap". This can be used to check if enough stars were identified. The starmaps are located in the output directory (variable: ''out_path'') and there in the subdirectory ''starmaps''. If not enough stars have been identified or noise has been falsely identified as stars, the ''sigma'' parameter should be adjusted in the call of ''main_extract''. The function ''main_extract'' has the nice feature that it marks the identified stars on a so called "starmap". This can be used to check if enough stars were identified. The starmaps are located in the output directory (variable: ''out_path'') and there in the subdirectory ''starmaps''. If not enough stars have been identified or noise has been falsely identified as stars, the ''sigma'' parameter should be adjusted in the call of ''main_extract''.
 +
 +++++ Quality Control I: Checking photometric errors |
 +
 +In addition to the starmap, the quality of the extraction can also be judged from the distribution of magnitude versus photometric error. The OST library provides the function ''plot_photometry_mag_vs_error'' for this. As with the diagnostic plots for the calibration further below, we first create a dedicated subdirectory for this:
 +
 +<code Python>
 +#   Prepare path for diagnostic plots
 +extraction_qc = str(diagnostics_dir(out_path, "extraction"))
 +</code>
 +
 +Then the plot can be created for both filters:
 +
 +<code Python>
 +#   Plot photometry vs. error
 +plot_photometry_mag_vs_error(V_image.photometry, extraction_qc, 'pdf', band_label='V')
 +plot_photometry_mag_vs_error(B_image.photometry, extraction_qc, 'pdf', band_label='B')
 +</code>
 +
 +A clear increase of the error towards fainter (larger) magnitudes is normal. Noticeable outliers or a very broad band can, however, also indicate problems with the extraction.
 +++++
 +
 === Preparing the extraction results === === Preparing the extraction results ===
  
Line 251: Line 276:
 #   Get table #   Get table
 photo_V = V_image.photometry photo_V = V_image.photometry
-photo_B = B_image.photometry +photo_B = B_image.photometry
 </code> </code>
  
Line 266: Line 291:
 === Cross correlation and sorting of results === === Cross correlation and sorting of results ===
  
-Next we have to identified those stars that are present in both filters. This is done using the ''astropy.coordinates'' package, more precisely using the correlation functions for datasets provided by this package. Since these functions work on the basis of celestial coordinates rather than pixel coordinates, we need to convert our previously determined pixel coordinates into a suitable coordinate system. For this purpose it is convenient that we have determined the WCS before. +Next we have to identified those stars that are present in both filters. This is done using the ''astropy.coordinates'' package, more precisely using the correlation functions for datasets provided by this package. Since these functions work on the basis of celestial coordinates rather than pixel coordinates, we need to convert our previously determined pixel coordinates into a suitable coordinate system. For this purpose it is convenient that we have determined the WCS before.
  
-First, we create ''SkyCoord'' objects for each of the datasets from the two filters. These objects, once defined, allow us to output the coordinates in a variety of already predefined coordinate systems. Furthermore, and even more convenient, these objects are also accepted as arguments by a number of //Astropy// functions and classes. For this reason, you usually don't need to worry about which coordinate system you are working in, since this is all handled internally by //Astropy//. We define our ''SkyCoord'' objects using the option ''.from_pixel()'', which allows us to define them directly based on the pixel coordinates and the previously determined WCS (which we can take from the ''image'' object).  +First, we create ''SkyCoord'' objects for each of the datasets from the two filters. These objects, once defined, allow us to output the coordinates in a variety of already predefined coordinate systems. Furthermore, and even more convenient, these objects are also accepted as arguments by a number of //Astropy// functions and classes. For this reason, you usually don't need to worry about which coordinate system you are working in, since this is all handled internally by //Astropy//. We define our ''SkyCoord'' objects using the option ''.from_pixel()'', which allows us to define them directly based on the pixel coordinates and the previously determined WCS (which we can take from the ''image'' object).
  
 <code Python> <code Python>
Line 276: Line 301:
 </code> </code>
  
-These two ''SkyCoord'' objects can then be correlated with each other by means of the function ''search_around_sky''. In addition to the two ''SkyCoord'' objects this function needs as third argument the allowed tolerance in the coordinates (below which two objects from both datasets are still recognized as the same). In our case we choose a generous 2 arc seconds. The unit is defined here by the ''astropy.units'' package that we loaded above using the abbreviation ''u''. +These two ''SkyCoord'' objects can then be correlated with each other by means of the function ''search_around_sky''. In addition to the two ''SkyCoord'' objects this function needs as third argument the allowed tolerance in the coordinates (below which two objects from both datasets are still recognized as the same). In our case we choose a generous 2 arc seconds. The unit is defined here by the ''astropy.units'' package that we loaded above using the abbreviation ''u''.
  
 <code Python> <code Python>
Line 283: Line 308:
 </code> </code>
  
-The successfully mapped stars get one entry each in ''id_V'', ''id_B'', and ''d2''. These two first lists (more precisely Numpy arrays) contain the index values that these stars had in the original unsorted datasets. This means that we can use these index values to sort the original tables with the fluxes and star positions in such a way that they only contain stars that were detected in both images and that the order of the stars in both data sets is the same. This assignment is essential for the further procedure. +The successfully mapped stars get one entry each in ''id_V'', ''id_B'', and ''d2''. These two first lists (more precisely Numpy arrays) contain the index values that these stars had in the original unsorted datasets. This means that we can use these index values to sort the original tables with the fluxes and star positions in such a way that they only contain stars that were detected in both images and that the order of the stars in both data sets is the same. This assignment is essential for the further procedure.
  
 Before this can happen, however, potential multiple identifications must be sorted out. For example, it is possible that ''matching.search_around_sky()'' assigns object 3 from ''coords_V'' to both object 2 and object 4 from ''coords_B''. These duplicates are removed with Before this can happen, however, potential multiple identifications must be sorted out. For example, it is possible that ''matching.search_around_sky()'' assigns object 3 from ''coords_V'' to both object 2 and object 4 from ''coords_B''. These duplicates are removed with
Line 323: Line 348:
 </code> </code>
  
-Note that the magnitudes are determined only to an additive constant as long as no calibration has been performed. +Note that the magnitudes are determined only to an additive constant as long as no calibration has been performed.
  
 ===== Calibration ===== ===== Calibration =====
Line 349: Line 374:
  
 <code Python> <code Python>
-calib_tbl = v.query_region(V_image.coordinates_image_center, radius=V_image.field_of_view_x*u.arcmin)[0]+calib_tbl = v.query_region(V_image.coordinates_image_center, radius=V_image.field_of_view_x / 2. * u.arcmin)[0]
 </code> </code>
  
Line 355: Line 380:
  
 <WRAP center round important 90%> <WRAP center round important 90%>
-**Task:** Restrict the downloaded **APASS** catalog to all objects with ''V'' magnitudes in the 10 to 15 mag range. This will ensure that potentially overexposed as well as underexposed stars in our images are not used for the calibration. +**Task:** Restrict the downloaded **APASS** catalog to all objects with ''V'' magnitudes in the 10 to 15 mag range. This will ensure that potentially overexposed as well as underexposed stars in our images are not used for the calibration.
  
 Note: To accomplish this task, it might be helpful to learn a little about [[https://jakevdp.github.io/PythonDataScienceHandbook/02.06-boolean-arrays-and-masks.html|boolean masks, comparison operation, and boolean logic]]. Note: To accomplish this task, it might be helpful to learn a little about [[https://jakevdp.github.io/PythonDataScienceHandbook/02.06-boolean-arrays-and-masks.html|boolean masks, comparison operation, and boolean logic]].
Line 380: Line 405:
 <code Python> <code Python>
 #   Correlate extracted object position with calibration table #   Correlate extracted object position with calibration table
-ind_fit, ind_lit, _, _ = matching.search_around_sky(+ind_fit, ind_lit, d2, _ = matching.search_around_sky(
     coords_objs,     coords_objs,
     coord_calib,     coord_calib,
Line 387: Line 412:
 </code> </code>
  
-As also described above, the duplicates must now be sorted out: +As also described above, the duplicates must now be sorted out:
  
 <code Python> <code Python>
Line 403: Line 428:
 </code> </code>
  
-In this way, we again obtain index values that we can use to select the calibration stars both from the datasets for the two filters and from the downloaded catalog:  +In this way, we again obtain index values that we can use to select the calibration stars both from the datasets for the two filters and from the downloaded catalog:
  
 <code Python> <code Python>
Line 414: Line 439:
 </code> </code>
  
-++++ Quality Control I: Checking the calibration stars |+++++ Quality Control II: Checking the calibration stars |
 === Starmap === === Starmap ===
  
-One way to check the validity of the calibration stars is to display them on a starmap (similar to what the ''main_extract'' above does automatically). But now we want to display the downloaded star positions as well as the stars that were actually used for the calibration later on. For this purpose the OST library offers a suitable function (''starmap'') which can create such plots. This function can be loaded via +One way to check the validity of the calibration stars is to display them on a starmap (similar to what the ''main_extract'' above does automatically). But now we want to display the downloaded star positions as well as the stars that were actually used for the calibration later on. For this purpose the OST library offers a suitable function (''starmap'') which can create such plots. This function can be loaded via
  
 <code Python> <code Python>
Line 434: Line 459:
 <code Python> <code Python>
 tbl_xy_cali_all = Table( tbl_xy_cali_all = Table(
-    names=['id','x_centroid', 'y_centroid'],+    names=['id','xcentroid', 'ycentroid'],
     data=[np.arange(0,len(y_cali)), x_cali, y_cali]     data=[np.arange(0,len(y_cali)), x_cali, y_cali]
 ) )
Line 446: Line 471:
  
 tbl_xy_cali_s = Table( tbl_xy_cali_s = Table(
-    names=['id','x_centroid', 'y_centroid'],+    names=['id','xcentroid', 'ycentroid'],
     data=[np.arange(0,len(y_cali_s)), x_cali_s, y_cali_s]     data=[np.arange(0,len(y_cali_s)), x_cali_s, y_cali_s]
 ) )
Line 469: Line 494:
  
 tbl_xy_cali_correlated = Table( tbl_xy_cali_correlated = Table(
-    names=['id','x_centroid', 'y_centroid'],+    names=['id','xcentroid', 'ycentroid'],
     data=[np.arange(0,len(y_cali_correlated)), x_cali_correlated, y_cali_correlated]     data=[np.arange(0,len(y_cali_correlated)), x_cali_correlated, y_cali_correlated]
     )     )
Line 520: Line 545:
 plt.savefig(filename) plt.savefig(filename)
 </code> </code>
- +
 Here, ''filename'' is the file name or the path to the file. Alternatively, the plot can also be displayed directly via Here, ''filename'' is the file name or the path to the file. Alternatively, the plot can also be displayed directly via
  
Line 552: Line 577:
 #   Calculate separation between objects on the two images (inter-filter separations) #   Calculate separation between objects on the two images (inter-filter separations)
 sep_inter = coords_V[id_V].separation(coords_B[id_B]).arcsec sep_inter = coords_V[id_V].separation(coords_B[id_B]).arcsec
 +</code>
 +
 +We place all diagnostic plots in a separate subdirectory, apart from the starmaps, which have their own subdirectory:
 +
 +<code Python>
 +#   Prepare path for diagnostic plots
 +calibration_qc = str(diagnostics_dir(out_path, "calibration"))
 </code> </code>
  
Line 561: Line 593:
    np.asarray(sep_inter, dtype=float),    np.asarray(sep_inter, dtype=float),
    np.asarray(sep_cal, dtype=float),    np.asarray(sep_cal, dtype=float),
-   out_path,+   calibration_qc,
    'pdf',    'pdf',
    reference_filter='V',    reference_filter='V',
Line 587: Line 619:
 photo_B_sort['mag_cali'] = photo_B_sort['mag'] + ZP_B photo_B_sort['mag_cali'] = photo_B_sort['mag'] + ZP_B
 </code> </code>
 +
 +
 +++++ Quality Control III: Plot the instrumental magnitudes against the catalogue magnitudes and the zero-point deviations |
 +
 +In order to assess the quality of the magnitude calibration, we need to visualise both the distribution of magnitudes and the zero-point residuals. The OST library provides several plots for this purpose. To make the most of these, let us first define a few abbreviations:
 +
 +<code Python>
 +m_inst_v = np.asarray(photo_V_sort_calib['mag'].ravel(), dtype=float)
 +m_inst_b = np.asarray(photo_B_sort_calib['mag'].ravel(), dtype=float)
 +m_cat_v = np.asarray(calib_tbl_sort['Vmag'].ravel(), dtype=float)
 +m_cat_b = np.asarray(calib_tbl_sort['Bmag'].ravel(), dtype=float)
 +err_obs_v = (
 +    np.asarray(photo_V_sort_calib['mags_unc'], dtype=float)
 +    if 'mags_unc' in photo_V_sort_calib.colnames
 +    else None
 +)
 +err_obs_b = (
 +    np.asarray(photo_B_sort_calib['mags_unc'], dtype=float)
 +    if 'mags_unc' in photo_B_sort_calib.colnames
 +    else None
 +)
 +err_cat_v = (
 +    np.asarray(calib_tbl_sort['e_Vmag'], dtype=float)
 +    if 'e_Vmag' in calib_tbl_sort.colnames
 +    else None
 +)
 +err_cat_b = (
 +    np.asarray(calib_tbl_sort['e_Bmag'], dtype=float)
 +    if 'e_Bmag' in calib_tbl_sort.colnames
 +    else None
 +)
 +m_cal_v = m_inst_v + float(ZP_V)
 +m_cal_b = m_inst_b + float(ZP_B)
 +res_v = catalog_fit_residual(m_inst_v, m_cat_v, zero_point=float(ZP_V))
 +res_b = catalog_fit_residual(m_inst_b, m_cat_b, zero_point=float(ZP_B))
 +</code>
 +
 +We can then use the plots provided in the OST library to produce the necessary quality control figures:
 +
 +<code Python>
 +#   Plot instrumental vs. catalog magnitudes (V)
 +plot_instrumental_vs_catalog_magnitudes(
 +    m_cal_v,
 +    m_cat_v,
 +    calibration_qc,
 +    'pdf',
 +    band_label='V',
 +    show_one_to_one=True,
 +    x_label=r'$m_\mathrm{cal}$ [mag]',
 +    title='Cal stars: calibrated vs. catalog (V)',
 +    filename_stem='calibrated_vs_catalog_V',
 +    err_obs=err_obs_v,
 +    err_cat=err_cat_v,
 +    residual=res_v,
 +)
 +
 +#   Plot instrumental vs. catalog magnitudes (B)
 +plot_instrumental_vs_catalog_magnitudes(
 +    m_cal_b,
 +    m_cat_b,
 +    calibration_qc,
 +    'pdf',
 +    band_label='B',
 +    show_one_to_one=True,
 +    x_label=r'$m_\mathrm{cal}$ [mag]',
 +    title='Cal stars: calibrated vs. catalog (B)',
 +    filename_stem='calibrated_vs_catalog_B',
 +    err_obs=err_obs_b,
 +    err_cat=err_cat_b,
 +    residual=res_b,
 +)
 +
 +#   Plot zero point residuals distribution
 +plot_zeropoint_residual_distribution(
 +    None,
 +    calibration_qc,
 +    'pdf',
 +    residuals_by_band={
 +        'V': res_v,
 +        'B': res_b,
 +    },
 +    filename_stem='zeropoint_residuals_B_V',
 +)
 +
 +#   Plot zero point residuals vs. color index
 +color_lit = m_cat_b - m_cat_v
 +plot_zeropoint_residual_vs_color(
 +    color_lit,
 +    None,
 +    calibration_qc,
 +    'pdf',
 +    residuals_by_band={
 +        'V': res_v,
 +        'B': res_b,
 +    },
 +    color_label='B-V',
 +    title='Remaining color term with pure ZP?',
 +    filename_stem='zeropoint_residual_vs_color_B_V',
 +)
 +color_cal = calibrated_color(m_inst_b, m_inst_v, float(ZP_B), float(ZP_V))
 +
 +#   Plot calibration color vs. color
 +plot_calibration_color_color_cal_stars(
 +    color_lit,
 +    color_cal,
 +    calibration_qc,
 +    'pdf',
 +    color_label='B-V',
 +)
 +</code>
 +
 +++++
  
 ==== Saving the results ==== ==== Saving the results ====
Line 595: Line 739:
 #   Create new table for the CMD #   Create new table for the CMD
 results = Table() results = Table()
-results['id'] = photo_V_sort['id'] +results['id'] = photo_V_sort['id'].ravel() 
-results['x'] = photo_V_sort['x_fit'] +results['x'] = photo_V_sort['x_fit'].ravel() 
-results['y'] = photo_V_sort['y_fit'] +results['y'] = photo_V_sort['y_fit'].ravel() 
-results['B [mag]'] = photo_B_sort['mag_cali'] +results['B [mag]'] = photo_B_sort['mag_cali'].ravel() 
-results['V [mag]'] = photo_V_sort['mag_cali']+results['V [mag]'] = photo_V_sort['mag_cali'].ravel()
 </code> </code>
  
-If the new table is filled, //Astropy// allows to save this table very comfortably with the command ''.write''. As first argument we have to specify the path or file name under which the table should be saved. Furthermore we specify the ''format'' (we choose ''ascii'') and set the parameter ''overwrite'' to ''True'', so that if we run the script several times the current data will always be written to the file.  +If the new table is filled, //Astropy// allows to save this table very comfortably with the command ''.write''. As first argument we have to specify the path or file name under which the table should be saved. Furthermore we specify the ''format'' (we choose ''ascii'') and set the parameter ''overwrite'' to ''True'', so that if we run the script several times the current data will always be written to the file.
  
 <code Python> <code Python>
Line 611: Line 755:
 ===== Postprocessing ===== ===== Postprocessing =====
  
-If you look at the images of the star clusters you will notice that the star clusters usually occupy only a part of the field of view. Mostly this area will be between 30% and 60% of the field of view. So we probably observe beside the star clusters a number of other stars, so called field stars, which actually do not belong to our star cluster. Generally there will also be some stars between us and the star cluster. Since these stars most likely did not form together with the star cluster, these stars will spoil our results concerning the age determination or make them more difficult to interpret. +If you look at the images of the star clusters you will notice that the star clusters usually occupy only a part of the field of view. Mostly this area will be between 30% and 60% of the field of view. So we probably observe beside the star clusters a number of other stars, so called field stars, which actually do not belong to our star cluster. Generally there will also be some stars between us and the star cluster. Since these stars most likely did not form together with the star cluster, these stars will spoil our results concerning the age determination or make them more difficult to interpret.
  
 <WRAP center round important 90%> <WRAP center round important 90%>
 **Task:** **Task:**
-Try to limit the selection of stars to the most probable star cluster members. You have two possibilities, which can be used alternatively or additively.  +Try to limit the selection of stars to the most probable star cluster members. You have two possibilities, which can be used alternatively or additively. 
-  - Limit the selection of stars to e.g. 10 arc minutes around the central coordinates of the star cluster. +  - Limit the selection of stars to e.g. 10 arc minutes around the central coordinates of the star cluster. //(Note: this refers to the cataloged coordinates of the star cluster itself, e.g. obtainable via ''SkyCoord.from_name(name)'', not necessarily the centre of the image field ''V_image.coordinates_image_center''.)// 
-  - Download the data from the Gaia archive (catalog ID: ''I/350/gaiaedr3'') as demonstrated in the calibration above. From this data set, look in particular at the columns relating to the proper motion of the stars. Use this data to select the cluster members. +  - Download the data from the Gaia archive (catalog ID: ''I/355/gaiadr3'', Gaia DR3) as demonstrated in the calibration above. From this data set, look in particular at the columns relating to the parallax of the stars. Use this data to select the cluster members.
  
 Note: In any case, it is helpful to create starmaps (as described in the section "Checking the Calibration Stars") or similar plots that will help you to evaluate the results. Note: In any case, it is helpful to create starmaps (as described in the section "Checking the Calibration Stars") or similar plots that will help you to evaluate the results.
Line 631: Line 775:
 For the creation of the CMD a //Python// script is available, in which only a few paths and a few further parameters have to be adjusted. This script also offers the possibility to plot isochrones. We will go into this in more detail below. For the creation of the CMD a //Python// script is available, in which only a few paths and a few further parameters have to be adjusted. This script also offers the possibility to plot isochrones. We will go into this in more detail below.
  
-First you should copy the corresponding script ''3_plot_cmd.py'' from the directory ''~/scripts/n2/'' into the local working directory. Subsequently, the name of the star cluster (''nameOfStarcluster'') should be set and the path to the file saved above with the magnitudes should be added (''CMDFileName'').  +First you should copy the corresponding script ''3_plot_cmd.py'' from the directory ''~/scripts/n2/'' into the local working directory. Subsequently, the name of the star cluster (''nameOfStarcluster'') should be set and the path to the file saved above with the magnitudes should be added (''CMDFileName'').
  
 The script ''3_plot_cmd.py'' can be called as follows The script ''3_plot_cmd.py'' can be called as follows
  
-   python 3_plot_cmd.py   +   python 3_plot_cmd.py
  
-This script creates a PDF file with the apparent CMD. The axes scaling is done automatically. Since this is not always ideal due to outliers, the plot range should be adjusted via the variables ''x_Range_apparent'' and ''y_Range_apparent''. The quotation marks are simply to be replaced by the axis boundaries, such as ''x_Range_apparent = [-0.5, 2]''. +This script creates a PDF file with the apparent CMD. The axes scaling is done automatically. Since this is not always ideal due to outliers, the plot range should be adjusted via the variables ''x_Range_apparent'' and ''y_Range_apparent''. The quotation marks are simply to be replaced by the axis boundaries, such as ''x_Range_apparent = [-0.5, 2]''.
  
 <code Python> <code Python>
Line 657: Line 801:
 #       -> x and y range to plot (change according to your data) #       -> x and y range to plot (change according to your data)
 #       -> The plot range is automatically adjusted, if range is set to "" #       -> The plot range is automatically adjusted, if range is set to ""
-#   Apparent CMD:+#   Apparent CMD (also used for the isochrone overlay when 
 +#   apply_corrections_to = "isochrone"):
 x_Range_apparent=["",""] x_Range_apparent=["",""]
 y_Range_apparent=["",""] y_Range_apparent=["",""]
  
-#   Absolute CMD:+#   Absolute CMD (only when apply_corrections_to = "observation"):
 x_Range_absolute=["",""] x_Range_absolute=["",""]
 y_Range_absolute=["",""] y_Range_absolute=["",""]
Line 675: Line 820:
  
 $V_{0} = V - A_{V}$ $V_{0} = V - A_{V}$
-  +
 The reddening is mathematically described by the color excess $E_{(B-V)}$, the difference between the measured, uncorrected color $(B-V)$ (measured here) and the unreddened, "original" value $(B-V)_{0}$. The redding effects the magnitude, too. The correction term is $A_{V}$, which relates to $E_{(B-V)}$ by the reddening parameter $R_V$: The reddening is mathematically described by the color excess $E_{(B-V)}$, the difference between the measured, uncorrected color $(B-V)$ (measured here) and the unreddened, "original" value $(B-V)_{0}$. The redding effects the magnitude, too. The correction term is $A_{V}$, which relates to $E_{(B-V)}$ by the reddening parameter $R_V$:
  
 $A_{V} = R_V \cdot E_{(B-V)}$ $A_{V} = R_V \cdot E_{(B-V)}$
-   
-In the solar neighborhood $R_V$ usually is set to 3.1 ([[http://adsabs.harvard.edu/abs/1979MNRAS.187P..73S|Seaton 1979]]). Find an appropriate value for $E_{(B-V)}$ for the line of sight to the observed cluster, i.e. in //[[http://viz-old.u-strasbg.fr/viz-bin/VizieR-2|VizieR]]// or in //Simbad// by means of the papers that are associated with your object. In any case, refer to the used catalog or paper in your report! Apply this correction to your data and plot the CMD again.  
  
-Finally the apparent magnitudes should be converted into absolute magnitudes, so that later a comparison with isochrons is possible. For this, the corresponding distance modulus or the distance of the star cluster must be looked up in papers (publications) and the corresponding correction must be applied. +In the solar neighborhood $R_V$ usually is set to 3.1 ([[http://adsabs.harvard.edu/abs/1979MNRAS.187P..73S|Seaton 1979]]). Find an appropriate value for $E_{(B-V)}$ for the line of sight to the observed cluster, i.e. in //[[http://viz-old.u-strasbg.fr/viz-bin/VizieR-2|VizieR]]// or in //Simbad// by means of the papers that are associated with your object. In any case, refer to the used catalog or paper in your report! Apply this correction to your data and plot the CMD again. 
 + 
 +Finally the apparent magnitudes should be converted into absolute magnitudes, so that later a comparison with isochrons is possible. For this, the corresponding distance modulus or the distance of the star cluster must be looked up in papers (publications) and the corresponding correction must be applied.
  
 ==== Absolute CMD plot ==== ==== Absolute CMD plot ====
  
-After the $E_{(B-V)}$ and the distance or distance modulus for the corresponding star cluster have been figured out, these can be entered at the corresponding variables in the script ''3_plot_cmd.py''. ''m_M'' is the distance modulus. The remaining variables should be self-explanatory. If either ''m_M'' or ''distance'' is given, the script will create the absolute CMD as well as the apparent CMD. If it is necessary to adjust $R_V$ this can also be done. +After the $E_{(B-V)}$ and the distance or distance modulus for the corresponding star cluster have been figured out, these can be entered at the corresponding variables in the script ''3_plot_cmd.py''. ''m_M'' is the distance modulus. The remaining variables should be self-explanatory. If either ''m_M'' or ''distance'' is given, the script will create the absolute CMD as well as the apparent CMD. If it is necessary to adjust $R_V$ this can also be done.
  
 <code Python> <code Python>
Line 700: Line 845:
 distance = '?' distance = '?'
 </code> </code>
-    + 
-Note: In addition to these settings, there are a number of other configuration options, but we will not discuss them further at this point. +Note: In addition to these settings, there are a number of other configuration options, but we will not discuss them further at this point.
  
 ==== Plot isochrones ==== ==== Plot isochrones ====
Line 708: Line 853:
  
 Unfortunately, there is no uniform format for isochrones, which means that the script (''3_plot_cmd.py'') must be instructed to read these for each new "isochrone type" or each new "isochrone source". This is done using files in the so-called //YAML// format, which store the necessary configuration. For the isochrones contained in the OST library these configuration files can already be found in the script directory. An empty template file is also available there. Unfortunately, there is no uniform format for isochrones, which means that the script (''3_plot_cmd.py'') must be instructed to read these for each new "isochrone type" or each new "isochrone source". This is done using files in the so-called //YAML// format, which store the necessary configuration. For the isochrones contained in the OST library these configuration files can already be found in the script directory. An empty template file is also available there.
-In the script the selection of the respective "isochronous source" is done via the variable ''isochrone_configuration_file''. Here the name or the path to the respective //YAML// file has to be entered.   +In the script the selection of the respective "isochronous source" is done via the variable ''isochrone_configuration_file''. Here the name or the path to the respective //YAML// file has to be entered. 
-   + 
-++++ Do not display isochrones |  +++++ Do not display isochrones | 
-If no isochrones are to be displayed ''isochrone_configuration_file'' must be set to ""   +If no isochrones are to be displayed ''isochrone_configuration_file'' must be set to "" 
-++++ +++++
  
 For the [[http://stev.oapd.inaf.it/cgi-bin/cmd|PARCEC isochrones]] the configuration file looks like this: For the [[http://stev.oapd.inaf.it/cgi-bin/cmd|PARCEC isochrones]] the configuration file looks like this:
  
-   +
 <code YAML> <code YAML>
 --- ---
 #   PARCES isochrones (CMD 3.6) #   PARCES isochrones (CMD 3.6)
 +
 +#   Pick a grid below (do not comment/uncomment paths)
 +use: solar_1Gyr
  
 #   Files #   Files
-# isochrones: '~/isochrone_database/parsec_iso/3p6/solar_0p2Gyr/iso_parsec_0p2Gyr.dat' +grids: 
-# isochrones: '~/isochrone_database/parsec_iso/3p6/solar_0p5Gyr/iso_parsec_0p5Gyr.dat' +  solar_0p2Gyr: 
-isochrones: '~/isochrone_database/parsec_iso/3p6/solar_1Gyr/iso_parsec_1Gyr.dat'+    isochrones: '~/isochrone_database/parsec_iso/3p6/solar_0p2Gyr/iso_parsec_0p2Gyr.dat' 
 +  solar_0p5Gyr: 
 +    isochrones: '~/isochrone_database/parsec_iso/3p6/solar_0p5Gyr/iso_parsec_0p5Gyr.dat' 
 +  solar_1Gyr: 
 +    isochrones: '~/isochrone_database/parsec_iso/3p6/solar_1Gyr/iso_parsec_1Gyr.dat'
  
 #   Type #   Type
Line 739: Line 891:
 #         column-type is single, the name can be set to '-'. #         column-type is single, the name can be set to '-'.
 isochrone_column_type: isochrone_column_type:
-    'U': +    'U':
       - 'single'       - 'single'
       - 0       - 0
       - '-'       - '-'
-    'B': +    'B':
       - 'single'       - 'single'
       - 0       - 0
       - '-'       - '-'
-    'V': +    'V':
       - 'single'       - 'single'
       - 0       - 0
       - '-'       - '-'
-    'R': +    'R':
       - 'single'       - 'single'
       - 0       - 0
       - '-'       - '-'
- +
 #   ID of the columns in the isochrone data file containing the magnitudes #   ID of the columns in the isochrone data file containing the magnitudes
 #   and the age #   and the age
Line 764: Line 916:
     'R': 32     'R': 32
     'AGE': 3     'AGE': 3
-    +
 #   Keyword to identify a new isochrone #   Keyword to identify a new isochrone
 isochrone_keyword: '# Zini' isochrone_keyword: '# Zini'
Line 773: Line 925:
 #   Plot legend for isochrones? #   Plot legend for isochrones?
 isochrone_legend: true isochrone_legend: true
 +
 +#   Optional metadata for the CMD info box (omit any unknown field)
 +isochrone_set: "PARSEC 3.6"
 +FeH: 0.0
 ... ...
 </code> </code>
  
-''isochrones'' points to the file with the isochrones. Here ''isochrone_type'' is set to ''file'', which tells the script that all isochrones can be found in one file. An alternative is ''directory''. In this case the script expects the isochrones to be found in individual files in a specific directory and that the variable ''isochrones'' points to that directory. With ''isochrone_column'' you can specify the desired column numbers. ''isochrone_column_type'' specifies whether the magnitudes are given as colors or as "single" magnitudes. See the format description above for more information. The basic options here are ''color'' and ''single''. With ''isochrone_log_age'' you can specify whether the values in the age column are logarithmized or not. You can choose between ''True'' or ''False''. If the isochrones are all in one file, the script needs a keyword to recognize when an isochrone ends and the next one begins. This can be specified with the variable ''isochrone_keyword''. Finally, you can decide if you want to plot a legend for the isochrones. This is controlled by the variable ''isochrone_legend''. +''isochrones'' points to the file with the isochrones. Here ''isochrone_type'' is set to ''file'', which tells the script that all isochrones can be found in one file. An alternative is ''directory''. In this case the script expects the isochrones to be found in individual files in a specific directory and that the variable ''isochrones'' points to that directory. Use the ''use'' variable to select the desired set of isochrones. With ''isochrone_column'' you can specify the desired column numbers. ''isochrone_column_type'' specifies whether the magnitudes are given as colors or as "single" magnitudes. See the format description above for more information. The basic options here are ''color'' and ''single''. With ''isochrone_log_age'' you can specify whether the values in the age column are logarithmized or not. You can choose between ''True'' or ''False''. If the isochrones are all in one file, the script needs a keyword to recognize when an isochrone ends and the next one begins. This can be specified with the variable ''isochrone_keyword''. Finally, you can decide if you want to plot a legend for the isochrones. This is controlled by the variable ''isochrone_legend''. Optionally, metadata can then be added, which will appear in the plot as additional information.
  
 **Tip:** Usually there are isochrones from one source in different time resolutions and for different metallicities. These are then usually found in other files or folders. So it may be worthwhile to look in the database and adjust the entry for ''isochrones''. **Tip:** Usually there are isochrones from one source in different time resolutions and for different metallicities. These are then usually found in other files or folders. So it may be worthwhile to look in the database and adjust the entry for ''isochrones''.
Line 787: Line 943:
 A usual report is to be handed in. See the general overview about the required structure and content [[https://polaris.astro.physik.uni-potsdam.de/wiki/doku.php?id=en:praktikum:protocol|here]]. A usual report is to be handed in. See the general overview about the required structure and content [[https://polaris.astro.physik.uni-potsdam.de/wiki/doku.php?id=en:praktikum:protocol|here]].
  
 +/*
 For this observation, the theoretical overview in the report should describe open and globular cluster with emphasis on the observed kind, and their differences to other accumulations and groups of stars. Explain Hertzsprung-Russell diagrams (HRD) and the color-magnitude diagrams (CMD) and the difference between them. //Shortly// describe the evolution of stars of different masses in the context of a HRD. Explain the concepts of isochrones and the turn-off point and how one estimates the age of a cluster using them. For this observation, the theoretical overview in the report should describe open and globular cluster with emphasis on the observed kind, and their differences to other accumulations and groups of stars. Explain Hertzsprung-Russell diagrams (HRD) and the color-magnitude diagrams (CMD) and the difference between them. //Shortly// describe the evolution of stars of different masses in the context of a HRD. Explain the concepts of isochrones and the turn-off point and how one estimates the age of a cluster using them.
 +*/
  
-In the methods section describe the observations and the data reduction, highlight points that deviate from general description in here and list all the parameters you set for the extraction. Further, include all the plots of the data reduction in the report (a few in the text, most of them in the appendix). Also include any parameters for reddening, extinction, and distance that you adopt from the literature. +In the 'Methods' section, describe your observations and how you reduced the data. In particular, highlight any points that deviate from the general description provided here and list all parameters set for extraction. Furthermore, **include all the plots and figures** of the data reduction in the report. Also include any parameters for reddening, extinction, and distance that you adopt from the literature.
  
 The results part presents the cluster CMDs and describes the observable features in it. The results part presents the cluster CMDs and describes the observable features in it.
  • en/praktikum/photometrie_python.1776859781.txt.gz
  • Last modified: 2026/04/22 12:09
  • by rhainich