00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifdef HAVE_CONFIG_H
00031 #include <config.h>
00032 #endif
00033
00034 #include <stdio.h>
00035 #include <cpl.h>
00036 #include <math.h>
00037
00038 #include "vircam_utils.h"
00039 #include "vircam_mask.h"
00040 #include "vircam_dfs.h"
00041 #include "vircam_mods.h"
00042 #include "vircam_stats.h"
00043 #include "vircam_fits.h"
00044 #include "vircam_pfits.h"
00045 #include "vircam_channel.h"
00046 #include "vircam_paf.h"
00047 #include "vircam_wcsutils.h"
00048
00049
00050
00051 #define MEANTWI 1
00052 #define CONFMAP 2
00053 #define RATIMG 4
00054 #define STATS_TAB 8
00055
00056
00057
00058 static int vircam_twilight_flat_combine_create(cpl_plugin *) ;
00059 static int vircam_twilight_flat_combine_exec(cpl_plugin *) ;
00060 static int vircam_twilight_flat_combine_destroy(cpl_plugin *) ;
00061 static int vircam_twilight_flat_combine(cpl_parameterlist *, cpl_frameset *) ;
00062 static int vircam_twilight_flat_combine_save(cpl_frameset *framelist,
00063 cpl_parameterlist *parlist);
00064 static void vircam_twilight_flat_combine_dummy_products(void);
00065 static void vircam_twilight_flat_combine_normal(int jext);
00066 static int vircam_twilight_flat_combine_lastbit(int jext,
00067 cpl_frameset *framelist,
00068 cpl_parameterlist *parlist);
00069 static void vircam_twilight_flat_combine_init(void);
00070 static void vircam_twilight_flat_combine_tidy(int level);
00071
00072
00073
00074 static struct {
00075
00076
00077
00078 float lthr;
00079 float hthr;
00080 int combtype;
00081 int scaletype;
00082 int xrej;
00083 float thresh;
00084 int ncells;
00085 int extenum;
00086
00087
00088
00089 float flatrms;
00090 float flatratio_med;
00091 float flatratio_rms;
00092 float minv;
00093 float maxv;
00094 float avev;
00095 float photnoise;
00096 float snratio;
00097
00098 } vircam_twilight_flat_combine_config;
00099
00100
00101 static struct {
00102 vir_fits **good;
00103 int ngood;
00104 cpl_size *labels;
00105 cpl_frameset *twilightlist;
00106 cpl_frame *master_dark;
00107 cpl_frame *master_twilight_flat;
00108 vir_mask *master_mask;
00109 cpl_frame *chantab;
00110
00111 cpl_image *outimage;
00112 cpl_image *outconf;
00113 vir_fits **twilights;
00114 int ntwilights;
00115 cpl_propertylist *drs;
00116 cpl_propertylist *drs2;
00117 unsigned char *rejmask;
00118 unsigned char *rejplus;
00119 vir_fits *mfimage;
00120 cpl_image *ratioimg;
00121 cpl_table *ratioimstats;
00122 vir_tfits *ctable;
00123 vir_fits *mdark;
00124 cpl_propertylist *phupaf;
00125 } ps;
00126
00127 static int isfirst;
00128 static cpl_frame *product_frame_mean_twi = NULL;
00129 static cpl_frame *product_frame_conf = NULL;
00130 static cpl_frame *product_frame_ratioimg = NULL;
00131 static cpl_frame *product_frame_ratioimg_stats = NULL;
00132 static int we_expect;
00133 static int we_get;
00134
00135 static char vircam_twilight_flat_combine_description[] =
00136 "vircam_twilight_flat_combine -- VIRCAM twilight flat combine recipe.\n\n"
00137 "Combine a list of twilight flat frames into a mean frame. Optionally\n"
00138 "compare the output frame to a master twilight flat frame\n\n"
00139 "The program accepts the following files in the SOF:\n\n"
00140 " Tag Description\n"
00141 " -----------------------------------------------------------------------\n"
00142 " %-21s A list of raw twilight flat images\n"
00143 " %-21s A master dark frame\n"
00144 " %-21s Optional reference twilight flat frame\n"
00145 " %-21s Optional channel table or\n"
00146 " %-21s Optional initial channel table\n"
00147 " %-21s Optional master bad pixel map or\n"
00148 " %-21s Optional master confidence map\n"
00149 "If no reference twilight flat is made available, then no comparison will be\n"
00150 "done. This means there will be no output ratio image. If a master twilight\n"
00151 "is available, but no channel table is, then a ratio image will be formed\n"
00152 "but no stats will be written."
00153 "\n";
00154
00297
00298
00299
00307
00308
00309 int cpl_plugin_get_info(cpl_pluginlist *list) {
00310 cpl_recipe *recipe = cpl_calloc(1,sizeof(*recipe));
00311 cpl_plugin *plugin = &recipe->interface;
00312 char alldesc[SZ_ALLDESC];
00313 (void)snprintf(alldesc,SZ_ALLDESC,vircam_twilight_flat_combine_description,
00314 VIRCAM_TWI_RAW,VIRCAM_CAL_DARK,VIRCAM_REF_TWILIGHT_FLAT,
00315 VIRCAM_CAL_CHANTAB,VIRCAM_CAL_CHANTAB_INIT,VIRCAM_CAL_BPM,
00316 VIRCAM_CAL_CONF);
00317
00318 cpl_plugin_init(plugin,
00319 CPL_PLUGIN_API,
00320 VIRCAM_BINARY_VERSION,
00321 CPL_PLUGIN_TYPE_RECIPE,
00322 "vircam_twilight_flat_combine",
00323 "VIRCAM twilight combination recipe",
00324 alldesc,
00325 "Jim Lewis",
00326 "jrl@ast.cam.ac.uk",
00327 vircam_get_license(),
00328 vircam_twilight_flat_combine_create,
00329 vircam_twilight_flat_combine_exec,
00330 vircam_twilight_flat_combine_destroy);
00331
00332 cpl_pluginlist_append(list,plugin);
00333
00334 return(0);
00335 }
00336
00337
00346
00347
00348 static int vircam_twilight_flat_combine_create(cpl_plugin *plugin) {
00349 cpl_recipe *recipe;
00350 cpl_parameter *p;
00351
00352
00353
00354 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00355 recipe = (cpl_recipe *)plugin;
00356 else
00357 return(-1);
00358
00359
00360
00361 recipe->parameters = cpl_parameterlist_new();
00362
00363
00364
00365 p = cpl_parameter_new_value("vircam.vircam_twilight_flat_combine.lthr",
00366 CPL_TYPE_DOUBLE,
00367 "Low rejection threshold for underexpsed images",
00368 "vircam.vircam_twilight_flat_combine",
00369 4000.0);
00370 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"lthr");
00371 cpl_parameterlist_append(recipe->parameters,p);
00372
00373
00374
00375 p = cpl_parameter_new_value("vircam.vircam_twilight_flat_combine.hthr",
00376 CPL_TYPE_DOUBLE,
00377 "High rejection threshold for overexposed images",
00378 "vircam.vircam_twilight_flat_combine",
00379 12000.0);
00380 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"hthr");
00381 cpl_parameterlist_append(recipe->parameters,p);
00382
00383
00384
00385 p = cpl_parameter_new_range("vircam.vircam_twilight_flat_combine.combtype",
00386 CPL_TYPE_INT,
00387 "1 == Median,\n 2 == Mean",
00388 "vircam.vircam_twilight_flat_combine",
00389 1,1,2);
00390 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"combtype");
00391 cpl_parameterlist_append(recipe->parameters,p);
00392
00393
00394
00395 p = cpl_parameter_new_range("vircam.vircam_twilight_flat_combine.scaletype",
00396 CPL_TYPE_INT,
00397 "0 == none,\n 1 == additive offset,\n 2 == multiplicative offset,\n 3 == exposure time scaling + additive offset",
00398 "vircam.vircam_twilight_flat_combine",
00399 2,0,3);
00400 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"scaletype");
00401 cpl_parameterlist_append(recipe->parameters,p);
00402
00403
00404
00405 p = cpl_parameter_new_value("vircam.vircam_twilight_flat_combine.xrej",
00406 CPL_TYPE_BOOL,
00407 "True if using extra rejection cycle",
00408 "vircam.vircam_twilight_flat_combine",
00409 TRUE);
00410 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"xrej");
00411 cpl_parameterlist_append(recipe->parameters,p);
00412
00413
00414
00415 p = cpl_parameter_new_value("vircam.vircam_twilight_flat_combine.thresh",
00416 CPL_TYPE_DOUBLE,
00417 "Rejection threshold in sigma above background",
00418 "vircam.vircam_twilight_flat_combine",5.0);
00419 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"thresh");
00420 cpl_parameterlist_append(recipe->parameters,p);
00421
00422
00423
00424 p = cpl_parameter_new_enum("vircam.vircam_twilight_flat_combine.ncells",
00425 CPL_TYPE_INT,
00426 "Number of cells for data channel stats",
00427 "vircam.vircam_twilight_flat_combine",8,7,1,2,4,
00428 8,16,32,64);
00429 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"ncells");
00430 cpl_parameterlist_append(recipe->parameters,p);
00431
00432
00433
00434 p = cpl_parameter_new_range("vircam.vircam_twilight_flat_combine.extenum",
00435 CPL_TYPE_INT,
00436 "Extension number to be done, 0 == all",
00437 "vircam.vircam_twilight_flat_combine",
00438 1,0,16);
00439 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"ext");
00440 cpl_parameterlist_append(recipe->parameters,p);
00441
00442
00443
00444 return(0);
00445 }
00446
00447
00448
00454
00455
00456 static int vircam_twilight_flat_combine_exec(cpl_plugin *plugin) {
00457 cpl_recipe *recipe;
00458
00459
00460
00461 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00462 recipe = (cpl_recipe *)plugin;
00463 else
00464 return(-1);
00465
00466 return(vircam_twilight_flat_combine(recipe->parameters,recipe->frames));
00467 }
00468
00469
00475
00476
00477 static int vircam_twilight_flat_combine_destroy(cpl_plugin *plugin) {
00478 cpl_recipe *recipe ;
00479
00480
00481
00482 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00483 recipe = (cpl_recipe *)plugin;
00484 else
00485 return(-1);
00486
00487 cpl_parameterlist_delete(recipe->parameters);
00488 return(0);
00489 }
00490
00491
00498
00499
00500 static int vircam_twilight_flat_combine(cpl_parameterlist *parlist,
00501 cpl_frameset *framelist) {
00502 const char *fctid="vircam_twilight_flat_combine";
00503 int j,jst,jfn,retval,status,live,nx,ny,ndit,npts;
00504 cpl_size nlab;
00505 long i;
00506 cpl_parameter *p;
00507 vir_fits *ff;
00508 cpl_propertylist *pp;
00509 cpl_image *im1,*im2,*newim,*diffim;
00510 double val1,val2,scl;
00511 float *data,med,mad;
00512 unsigned char *bpm;
00513
00514
00515
00516 if (framelist == NULL || cpl_frameset_get_size(framelist) <= 0) {
00517 cpl_msg_error(fctid,"Input framelist NULL or has no input data");
00518 return(-1);
00519 }
00520
00521
00522
00523 if (vircam_frameset_fexists(framelist) != VIR_OK) {
00524 cpl_msg_error(fctid,"Input frameset is missing files. Check SOF");
00525 return(-1);
00526 }
00527
00528
00529
00530 vircam_twilight_flat_combine_init();
00531 we_expect = MEANTWI + CONFMAP;
00532
00533
00534
00535 p = cpl_parameterlist_find(parlist,"vircam.vircam_twilight_flat_combine.lthr");
00536 vircam_twilight_flat_combine_config.lthr =
00537 (float)cpl_parameter_get_double(p);
00538 p = cpl_parameterlist_find(parlist,
00539 "vircam.vircam_twilight_flat_combine.hthr");
00540 vircam_twilight_flat_combine_config.hthr =
00541 (float)cpl_parameter_get_double(p);
00542 p = cpl_parameterlist_find(parlist,
00543 "vircam.vircam_twilight_flat_combine.combtype");
00544 vircam_twilight_flat_combine_config.combtype = cpl_parameter_get_int(p);
00545 p = cpl_parameterlist_find(parlist,
00546 "vircam.vircam_twilight_flat_combine.scaletype");
00547 vircam_twilight_flat_combine_config.scaletype = cpl_parameter_get_int(p);
00548 p = cpl_parameterlist_find(parlist,
00549 "vircam.vircam_twilight_flat_combine.xrej");
00550 vircam_twilight_flat_combine_config.xrej = cpl_parameter_get_bool(p);
00551 p = cpl_parameterlist_find(parlist,
00552 "vircam.vircam_twilight_flat_combine.thresh");
00553 vircam_twilight_flat_combine_config.thresh =
00554 (float)cpl_parameter_get_double(p);
00555 p = cpl_parameterlist_find(parlist,
00556 "vircam.vircam_twilight_flat_combine.ncells");
00557 vircam_twilight_flat_combine_config.ncells = cpl_parameter_get_int(p);
00558 p = cpl_parameterlist_find(parlist,
00559 "vircam.vircam_twilight_flat_combine.extenum");
00560 vircam_twilight_flat_combine_config.extenum = cpl_parameter_get_int(p);
00561
00562
00563
00564 if (vircam_dfs_set_groups(framelist) != VIR_OK) {
00565 cpl_msg_error(fctid,"Cannot identify RAW and CALIB frames");
00566 vircam_twilight_flat_combine_tidy(2);
00567 return(-1);
00568 }
00569
00570
00571
00572 if ((ps.labels = cpl_frameset_labelise(framelist,vircam_compare_tags,
00573 &nlab)) == NULL) {
00574 cpl_msg_error(fctid,"Cannot labelise the input frames");
00575 vircam_twilight_flat_combine_tidy(2);
00576 return(-1);
00577 }
00578 if ((ps.twilightlist = vircam_frameset_subgroup(framelist,ps.labels,nlab,
00579 VIRCAM_TWI_RAW)) == NULL) {
00580 cpl_msg_error(fctid,"Cannot find twilight frames in input frameset");
00581 vircam_twilight_flat_combine_tidy(2);
00582 return(-1);
00583 }
00584 ps.ntwilights = cpl_frameset_get_size(ps.twilightlist);
00585
00586
00587
00588 if ((ps.master_dark = vircam_frameset_subgroup_1(framelist,ps.labels,nlab,
00589 VIRCAM_CAL_DARK)) == NULL) {
00590 cpl_msg_error(fctid,"No master dark found");
00591 vircam_twilight_flat_combine_tidy(2);
00592 return(-1);
00593 }
00594
00595
00596
00597 if ((ps.master_twilight_flat = vircam_frameset_subgroup_1(framelist,
00598 ps.labels,nlab,VIRCAM_REF_TWILIGHT_FLAT)) == NULL)
00599 cpl_msg_info(fctid,"No master twilight flat found -- no ratio image will be formed");
00600 else
00601 we_expect |= RATIMG;
00602
00603
00604
00605
00606 ps.master_mask = vircam_mask_define(framelist,ps.labels,nlab);
00607
00608
00609
00610 if ((ps.chantab = vircam_frameset_subgroup_1(framelist,ps.labels,nlab,
00611 VIRCAM_CAL_CHANTAB)) == NULL) {
00612 if ((ps.chantab = vircam_frameset_subgroup_1(framelist,ps.labels,nlab,
00613 VIRCAM_CAL_CHANTAB_INIT)) == NULL) {
00614 cpl_msg_info(fctid,"No channel table found -- no ratio image stats and no linearisation will be done");
00615 } else {
00616 cpl_msg_info(fctid,"Channel table is labelled INIT -- no linearisation will be done");
00617 if (we_expect & RATIMG)
00618 we_expect |= STATS_TAB;
00619 }
00620 } else if (we_expect & RATIMG) {
00621 we_expect |= STATS_TAB;
00622 }
00623
00624
00625
00626 pp = cpl_propertylist_load(cpl_frame_get_filename(cpl_frameset_get_frame(ps.twilightlist,0)),0);
00627 if (vircam_pfits_get_ndit(pp,&ndit) != VIR_OK) {
00628 cpl_msg_error(fctid,"No value for NDIT available");
00629 freepropertylist(pp);
00630 vircam_twilight_flat_combine_tidy(2);
00631 return(-1);
00632 }
00633 cpl_propertylist_delete(pp);
00634
00635
00636
00637
00638
00639 vircam_exten_range(vircam_twilight_flat_combine_config.extenum,
00640 (const cpl_frame *)cpl_frameset_get_frame(ps.twilightlist,0),
00641 &jst,&jfn);
00642 if (jst == -1 || jfn == -1) {
00643 cpl_msg_error(fctid,"Unable to continue");
00644 vircam_twilight_flat_combine_tidy(2);
00645 return(-1);
00646 }
00647
00648
00649
00650 ps.good = cpl_malloc(ps.ntwilights*sizeof(vir_fits *));
00651
00652
00653
00654 for (j = jst; j <= jfn; j++) {
00655 status = VIR_OK;
00656 we_get = 0;
00657 isfirst = (j == jst);
00658
00659
00660
00661 ps.twilights = vircam_fits_load_list(ps.twilightlist,CPL_TYPE_FLOAT,j);
00662 if (ps.twilights == NULL) {
00663 cpl_msg_info(fctid,
00664 "Extension %" CPL_SIZE_FORMAT " twilights wouldn't load",
00665 (cpl_size)j);
00666 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00667 if (retval != 0)
00668 return(-1);
00669 continue;
00670 }
00671
00672
00673
00674 ps.ngood = 0;
00675 for (i = 0; i < ps.ntwilights; i++) {
00676 ff = ps.twilights[i];
00677 vircam_pfits_get_detlive(vircam_fits_get_ehu(ff),&live);
00678 if (! live) {
00679 cpl_msg_info(fctid,"Detector flagged dead %s",
00680 vircam_fits_get_fullname(ff));
00681 vircam_fits_set_error(ff,VIR_FATAL);
00682 } else {
00683 ps.good[ps.ngood] = ff;
00684 ps.ngood += 1;
00685 }
00686 }
00687
00688
00689
00690
00691 if (ps.ngood == 0) {
00692 cpl_msg_info(fctid,"All images flagged bad for this extension");
00693 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00694 if (retval != 0)
00695 return(-1);
00696 continue;
00697 }
00698
00699
00700
00701 vircam_overexp(ps.good,&(ps.ngood),ndit,
00702 vircam_twilight_flat_combine_config.lthr,
00703 vircam_twilight_flat_combine_config.hthr,0,
00704 &(vircam_twilight_flat_combine_config.minv),
00705 &(vircam_twilight_flat_combine_config.maxv),
00706 &(vircam_twilight_flat_combine_config.avev));
00707
00708
00709
00710
00711 if (ps.ngood == 0) {
00712 cpl_msg_info(fctid,"All images either under or overexposed");
00713 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00714 if (retval != 0)
00715 return(-1);
00716 continue;
00717 }
00718
00719
00720
00721 nx = (int)cpl_image_get_size_x(vircam_fits_get_image(ps.good[0]));
00722 ny = (int)cpl_image_get_size_y(vircam_fits_get_image(ps.good[0]));
00723 if (vircam_mask_load(ps.master_mask,j,nx,ny) == VIR_FATAL) {
00724 cpl_msg_info(fctid,
00725 "Unable to load mask image %s[%" CPL_SIZE_FORMAT "]",
00726 vircam_mask_get_filename(ps.master_mask),
00727 (cpl_size)j);
00728 cpl_msg_info(fctid,"Forcing all pixels to be good from now on");
00729 vircam_mask_force(ps.master_mask,nx,ny);
00730 }
00731
00732
00733
00734
00735 if (ps.ngood > 1) {
00736 i = ps.ngood/2 - 1;
00737 im1 = vircam_fits_get_image(ps.good[i]);
00738 im2 = vircam_fits_get_image(ps.good[i+1]);
00739 val1 = cpl_image_get_median_window(im1,500,500,1000,1000);
00740 val2 = cpl_image_get_median_window(im2,500,500,1000,1000);
00741 val1 /= (double)ndit;
00742 val2 /= (double)ndit;
00743 scl = val1/val2;
00744 newim = cpl_image_multiply_scalar_create(im2,scl);
00745 diffim = cpl_image_subtract_create(im1,newim);
00746 cpl_image_delete(newim);
00747 data = cpl_image_get_data_float(diffim);
00748 bpm = vircam_mask_get_data(ps.master_mask);
00749 npts = nx*ny;
00750 vircam_medmad(data,bpm,npts,&med,&mad);
00751 mad *= 1.48/CPL_MATH_SQRT2;
00752 vircam_twilight_flat_combine_config.photnoise = mad;
00753 vircam_twilight_flat_combine_config.snratio =
00754 val1*sqrt((double)(ps.ngood))/mad;
00755 cpl_image_delete(diffim);
00756 } else {
00757 vircam_twilight_flat_combine_config.photnoise = 0.0;
00758 vircam_twilight_flat_combine_config.snratio = 0.0;
00759 }
00760
00761
00762
00763
00764 ps.mdark = vircam_fits_load(ps.master_dark,CPL_TYPE_FLOAT,j);
00765 if (ps.mdark == NULL) {
00766 cpl_msg_info(fctid,
00767 "Can't load master dark for extension %" CPL_SIZE_FORMAT,
00768 (cpl_size)j);
00769 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00770 if (retval != 0)
00771 return(-1);
00772 continue;
00773 } else if (vircam_is_dummy(vircam_fits_get_ehu(ps.mdark))) {
00774 cpl_msg_info(fctid,
00775 "Can't master dark extension %" CPL_SIZE_FORMAT " is a dummy",
00776 (cpl_size)j);
00777 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00778 if (retval != 0)
00779 return(-1);
00780 continue;
00781 }
00782
00783
00784
00785 cpl_msg_info(fctid,"Dark correcting extension %" CPL_SIZE_FORMAT,
00786 (cpl_size)j);
00787 for (i = 0; i < ps.ngood; i++)
00788 vircam_darkcor((ps.good)[i],ps.mdark,1.0,&status);
00789
00790
00791
00792
00793 if (ps.chantab != NULL) {
00794 ps.ctable = vircam_tfits_load(ps.chantab,j);
00795 if (ps.ctable == NULL) {
00796 cpl_msg_info(fctid,
00797 "Channel table extension %" CPL_SIZE_FORMAT " won't load",
00798 (cpl_size)j);
00799 } else if (vircam_chantab_verify(vircam_tfits_get_table(ps.ctable)) != VIR_OK) {
00800 cpl_msg_info(fctid,
00801 "Channel table extension %" CPL_SIZE_FORMAT " has errors",
00802 (cpl_size)j);
00803 freetfits(ps.ctable);
00804 } else {
00805 pp = cpl_propertylist_load(cpl_frame_get_filename(ps.chantab),
00806 (cpl_size)j);
00807 if (vircam_is_dummy(pp)) {
00808 cpl_msg_info(fctid,
00809 "Channel table extensions %" CPL_SIZE_FORMAT " is a dummy",
00810 (cpl_size)j);
00811 freetfits(ps.ctable);
00812 }
00813 freepropertylist(pp);
00814 }
00815 } else
00816 ps.ctable = NULL;
00817
00818
00819
00820
00821 if (ps.ctable != NULL) {
00822 cpl_msg_info(fctid,
00823 "Linearising extension %" CPL_SIZE_FORMAT,
00824 (cpl_size)j);
00825 for (i = 0; i < ps.ngood; i++)
00826 (void)vircam_lincor((ps.good)[i],ps.ctable,1,ndit,&status);
00827 }
00828
00829
00830
00831 for (i = 0; i < ps.ngood; i++)
00832 (void)vircam_nditcor((ps.good)[i],ndit,&status);
00833
00834
00835
00836 cpl_msg_info(fctid,
00837 "Doing combination for extension %" CPL_SIZE_FORMAT,
00838 (cpl_size)j);
00839 (void)vircam_imcombine(ps.good,ps.ngood,
00840 vircam_twilight_flat_combine_config.combtype,
00841 vircam_twilight_flat_combine_config.scaletype,
00842 vircam_twilight_flat_combine_config.xrej,
00843 vircam_twilight_flat_combine_config.thresh,
00844 &(ps.outimage),&(ps.rejmask),&(ps.rejplus),
00845 &(ps.drs),&status);
00846
00847
00848
00849
00850 if (status == VIR_OK) {
00851 we_get |= MEANTWI;
00852 vircam_twilight_flat_combine_normal(j);
00853 } else {
00854 cpl_msg_info(fctid,"A processing step failed");
00855 }
00856
00857
00858
00859 retval = vircam_twilight_flat_combine_lastbit(j,framelist,parlist);
00860 if (retval != 0)
00861 return(-1);
00862
00863 }
00864 vircam_twilight_flat_combine_tidy(2);
00865 return(0);
00866 }
00867
00868
00869
00876
00877
00878 static int vircam_twilight_flat_combine_save(cpl_frameset *framelist,
00879 cpl_parameterlist *parlist) {
00880 cpl_propertylist *plist,*elist,*p,*pafprop;
00881 int status;
00882 float val;
00883 const char *fctid = "vircam_twilight_flat_combine_save";
00884 const char *outfile = "twilightcomb.fits";
00885 const char *outdiff = "twilightratio.fits";
00886 const char *outdimst = "twilightratiotab.fits";
00887 const char *outconf = "twilightconf.fits";
00888 const char *outfilepaf = "twilightcomb";
00889 const char *outdiffpaf = "twilightratio";
00890 const char *recipeid = "vircam_twilight_flat_combine";
00891
00892
00893
00894
00895 if (isfirst) {
00896
00897
00898
00899 product_frame_mean_twi = cpl_frame_new();
00900 cpl_frame_set_filename(product_frame_mean_twi,outfile);
00901 cpl_frame_set_tag(product_frame_mean_twi,VIRCAM_PRO_TWILIGHT_FLAT);
00902 cpl_frame_set_type(product_frame_mean_twi,CPL_FRAME_TYPE_IMAGE);
00903 cpl_frame_set_group(product_frame_mean_twi,CPL_FRAME_GROUP_PRODUCT);
00904 cpl_frame_set_level(product_frame_mean_twi,CPL_FRAME_LEVEL_FINAL);
00905
00906
00907
00908 plist = vircam_fits_get_phu(ps.twilights[0]);
00909 ps.phupaf = vircam_paf_phu_items(plist);
00910 if (ps.master_twilight_flat != NULL) {
00911 cpl_propertylist_update_string(ps.phupaf,"REF_TWILIGHT",
00912 cpl_frame_get_filename(ps.master_twilight_flat));
00913 cpl_propertylist_set_comment(ps.phupaf,"REF_TWILIGHT",
00914 "Reference twilight flat used");
00915 }
00916 vircam_dfs_set_product_primary_header(plist,product_frame_mean_twi,
00917 framelist,parlist,
00918 (char *)recipeid,
00919 "PRO-1.15",NULL,0);
00920
00921
00922
00923 if (cpl_image_save(NULL,outfile,CPL_TYPE_UCHAR,plist,
00924 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
00925 cpl_msg_error(fctid,"Cannot save product PHU");
00926 cpl_frame_delete(product_frame_mean_twi);
00927 return(-1);
00928 }
00929 cpl_frameset_insert(framelist,product_frame_mean_twi);
00930
00931
00932
00933
00934 product_frame_conf = cpl_frame_new();
00935 cpl_frame_set_filename(product_frame_conf,outconf);
00936 cpl_frame_set_tag(product_frame_conf,VIRCAM_PRO_CONF);
00937 cpl_frame_set_type(product_frame_conf,CPL_FRAME_TYPE_IMAGE);
00938 cpl_frame_set_group(product_frame_conf,CPL_FRAME_GROUP_PRODUCT);
00939 cpl_frame_set_level(product_frame_conf,CPL_FRAME_LEVEL_FINAL);
00940
00941
00942
00943 plist = vircam_fits_get_phu(ps.twilights[0]);
00944 vircam_dfs_set_product_primary_header(plist,product_frame_conf,
00945 framelist,parlist,
00946 (char *)recipeid,"PRO-1.15",
00947 NULL,0);
00948
00949
00950
00951 if (cpl_image_save(NULL,outconf,CPL_TYPE_UCHAR,plist,
00952 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
00953 cpl_msg_error(fctid,"Cannot save product PHU");
00954 cpl_frame_delete(product_frame_conf);
00955 return(-1);
00956 }
00957 cpl_frameset_insert(framelist,product_frame_conf);
00958
00959
00960
00961 if (we_expect & RATIMG) {
00962 product_frame_ratioimg = cpl_frame_new();
00963 cpl_frame_set_filename(product_frame_ratioimg,outdiff);
00964 cpl_frame_set_tag(product_frame_ratioimg,
00965 VIRCAM_PRO_RATIOIMG_TWILIGHT_FLAT);
00966 cpl_frame_set_type(product_frame_ratioimg,CPL_FRAME_TYPE_IMAGE);
00967 cpl_frame_set_group(product_frame_ratioimg,
00968 CPL_FRAME_GROUP_PRODUCT);
00969 cpl_frame_set_level(product_frame_ratioimg,CPL_FRAME_LEVEL_FINAL);
00970
00971
00972
00973 plist = vircam_fits_get_phu(ps.twilights[0]);
00974 vircam_dfs_set_product_primary_header(plist,product_frame_ratioimg,
00975 framelist,parlist,
00976 (char *)recipeid,"PRO-1.15",
00977 NULL,0);
00978
00979
00980
00981 if (cpl_image_save(NULL,outdiff,CPL_TYPE_CHAR,plist,
00982 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
00983 cpl_msg_error(fctid,"Cannot save product PHU");
00984 cpl_frame_delete(product_frame_ratioimg);
00985 return(-1);
00986 }
00987 cpl_frameset_insert(framelist,product_frame_ratioimg);
00988 }
00989
00990
00991
00992
00993 if (we_expect & STATS_TAB) {
00994 product_frame_ratioimg_stats = cpl_frame_new();
00995 cpl_frame_set_filename(product_frame_ratioimg_stats,outdimst);
00996 cpl_frame_set_tag(product_frame_ratioimg_stats,
00997 VIRCAM_PRO_RATIOIMG_TWILIGHT_FLAT_STATS);
00998 cpl_frame_set_type(product_frame_ratioimg_stats,
00999 CPL_FRAME_TYPE_TABLE);
01000 cpl_frame_set_group(product_frame_ratioimg_stats,
01001 CPL_FRAME_GROUP_PRODUCT);
01002 cpl_frame_set_level(product_frame_ratioimg_stats,
01003 CPL_FRAME_LEVEL_FINAL);
01004
01005
01006
01007 plist = vircam_fits_get_phu(ps.twilights[0]);
01008 vircam_dfs_set_product_primary_header(plist,
01009 product_frame_ratioimg_stats,
01010 framelist,parlist,
01011 (char *)recipeid,"PRO-1.15",
01012 NULL,0);
01013
01014
01015
01016 elist = vircam_fits_get_ehu(ps.twilights[0]);
01017 p = cpl_propertylist_duplicate(elist);
01018 vircam_merge_propertylists(p,ps.drs);
01019 if (! (we_get & STATS_TAB))
01020 vircam_dummy_property(p);
01021 vircam_dfs_set_product_exten_header(p,product_frame_ratioimg_stats,
01022 framelist,parlist,
01023 (char *)recipeid,
01024 "PRO-1.15",NULL);
01025 status = VIR_OK;
01026 vircam_removewcs(p,&status);
01027
01028
01029
01030 if (cpl_table_save(ps.ratioimstats,plist,p,outdimst,
01031 CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
01032 cpl_msg_error(fctid,"Cannot save product table extension");
01033 cpl_propertylist_delete(p);
01034 return(-1);
01035 }
01036 cpl_propertylist_delete(p);
01037 cpl_frameset_insert(framelist,product_frame_ratioimg_stats);
01038 }
01039 }
01040
01041
01042
01043 plist = vircam_fits_get_ehu(ps.twilights[0]);
01044 vircam_merge_propertylists(plist,ps.drs);
01045 cpl_propertylist_update_int(plist,"ESO PRO DATANCOM",ps.ngood);
01046
01047
01048
01049 p = cpl_propertylist_duplicate(plist);
01050 if (! (we_get & MEANTWI))
01051 vircam_dummy_property(p);
01052 vircam_dfs_set_product_exten_header(p,product_frame_mean_twi,framelist,
01053 parlist,(char *)recipeid,
01054 "PRO-1.15",NULL);
01055
01056
01057
01058 cpl_propertylist_update_float(p,"ESO QC FLATRMS",
01059 vircam_twilight_flat_combine_config.flatrms);
01060 cpl_propertylist_set_comment(p,"ESO QC FLATRMS","RMS of output flat");
01061 cpl_propertylist_update_float(p,"ESO QC FLATMIN",
01062 vircam_twilight_flat_combine_config.minv);
01063 cpl_propertylist_set_comment(p,"ESO QC FLATMIN","Ensemble minimum");
01064 cpl_propertylist_update_float(p,"ESO QC FLATMAX",
01065 vircam_twilight_flat_combine_config.maxv);
01066 cpl_propertylist_set_comment(p,"ESO QC FLATMAX","Ensemble maximum");
01067 cpl_propertylist_update_float(p,"ESO QC FLATAVG",
01068 vircam_twilight_flat_combine_config.avev);
01069 cpl_propertylist_set_comment(p,"ESO QC FLATAVG","Ensemble average");
01070 val = vircam_twilight_flat_combine_config.maxv -
01071 vircam_twilight_flat_combine_config.minv;
01072 cpl_propertylist_update_float(p,"ESO QC FLATRNG",val);
01073 cpl_propertylist_set_comment(p,"ESO QC FLATRNG","Ensemble range");
01074 cpl_propertylist_update_float(p,"ESO QC TWIPHOT",
01075 vircam_twilight_flat_combine_config.photnoise);
01076 cpl_propertylist_set_comment(p,"ESO QC TWIPHOT",
01077 "[adu] Estimated photon noise");
01078 cpl_propertylist_update_float(p,"ESO QC TWISNRATIO",
01079 vircam_twilight_flat_combine_config.snratio);
01080 cpl_propertylist_set_comment(p,"ESO QC TWISNRATIO","Estimated S/N ratio");
01081 if (cpl_image_save(ps.outimage,outfile,CPL_TYPE_FLOAT,p,
01082 CPL_IO_EXTEND) != CPL_ERROR_NONE) {
01083 cpl_msg_error(fctid,"Cannot save product image extension");
01084 cpl_propertylist_delete(p);
01085 return(-1);
01086 }
01087
01088
01089
01090 pafprop = vircam_paf_req_items(p);
01091 vircam_merge_propertylists(pafprop,ps.phupaf);
01092 vircam_paf_append(pafprop,vircam_fits_get_phu(ps.twilights[0]),
01093 "ESO INS FILT1 NAME");
01094 vircam_paf_append(pafprop,p,"ESO PRO CATG");
01095 vircam_paf_append(pafprop,p,"ESO PRO DATANCOM");
01096 vircam_paf_append(pafprop,p,"ESO DET NDIT");
01097 if (vircam_paf_print((char *)outfilepaf,
01098 "VIRCAM/vircam_twilight_flat_combine",
01099 "QC file",pafprop) != VIR_OK)
01100 cpl_msg_warning(fctid,"Unable to save PAF for mean twilight");
01101 cpl_propertylist_delete(pafprop);
01102 cpl_propertylist_delete(p);
01103
01104
01105
01106 if (we_expect & RATIMG) {
01107 p = cpl_propertylist_duplicate(plist);
01108 if (! (we_get & RATIMG))
01109 vircam_dummy_property(p);
01110 cpl_propertylist_update_float(p,"ESO QC FLATRATIO_MED",
01111 vircam_twilight_flat_combine_config.flatratio_med);
01112 cpl_propertylist_set_comment(p,"ESO QC FLATRATIO_MED",
01113 "Median of ratio map");
01114 cpl_propertylist_update_float(p,"ESO QC FLATRATIO_RMS",
01115 vircam_twilight_flat_combine_config.flatratio_rms);
01116 cpl_propertylist_set_comment(p,"ESO QC FLATRATIO_RMS",
01117 "RMS of ratio map");
01118 vircam_dfs_set_product_exten_header(p,product_frame_ratioimg,
01119 framelist,parlist,(char *)recipeid,
01120 "PRO-1.15",NULL);
01121 if (cpl_image_save(ps.ratioimg,outdiff,CPL_TYPE_FLOAT,p,
01122 CPL_IO_EXTEND) != CPL_ERROR_NONE) {
01123 cpl_propertylist_delete(p);
01124 cpl_msg_error(fctid,"Cannot save product image extension");
01125 return(-1);
01126 }
01127
01128
01129
01130 pafprop = vircam_paf_req_items(p);
01131 vircam_merge_propertylists(pafprop,ps.phupaf);
01132 vircam_paf_append(pafprop,vircam_fits_get_phu(ps.twilights[0]),
01133 "ESO INS FILT1 NAME");
01134 vircam_paf_append(pafprop,p,"ESO PRO CATG");
01135 if (vircam_paf_print((char *)outdiffpaf,
01136 "VIRCAM/vircam_twilight_flat_combine",
01137 "QC file",pafprop) != VIR_OK)
01138 cpl_msg_warning(fctid,"Unable to save PAF for twilight ratio image");
01139 cpl_propertylist_delete(pafprop);
01140 cpl_propertylist_delete(p);
01141 }
01142
01143
01144
01145 if (! isfirst && (we_expect & STATS_TAB)) {
01146 p = cpl_propertylist_duplicate(plist);
01147 if (! (we_get & STATS_TAB))
01148 vircam_dummy_property(p);
01149 vircam_dfs_set_product_exten_header(p,product_frame_ratioimg_stats,
01150 framelist,parlist,(char *)recipeid,
01151 "PRO-1.15",NULL);
01152 status = VIR_OK;
01153 vircam_removewcs(p,&status);
01154 if (cpl_table_save(ps.ratioimstats,NULL,p,outdimst,CPL_IO_EXTEND)
01155 != CPL_ERROR_NONE) {
01156 cpl_msg_error(fctid,"Cannot save product table extension");
01157 cpl_propertylist_delete(p);
01158 return(-1);
01159 }
01160 cpl_propertylist_delete(p);
01161 }
01162
01163
01164
01165 vircam_merge_propertylists(plist,ps.drs2);
01166 p = cpl_propertylist_duplicate(plist);
01167 if (! (we_get & CONFMAP))
01168 vircam_dummy_property(p);
01169
01170
01171
01172 vircam_dfs_set_product_exten_header(p,product_frame_conf,framelist,
01173 parlist,(char *)recipeid,"PRO-1.15",
01174 NULL);
01175 if (cpl_image_save(ps.outconf,outconf,CPL_TYPE_SHORT,p,
01176 CPL_IO_EXTEND) != CPL_ERROR_NONE) {
01177 cpl_msg_error(fctid,"Cannot save product image extension");
01178 cpl_propertylist_delete(p);
01179 return(-1);
01180 }
01181 cpl_propertylist_delete(p);
01182
01183
01184
01185 return(0);
01186 }
01187
01188
01192
01193
01194 static void vircam_twilight_flat_combine_dummy_products(void) {
01195
01196
01197
01198 if (we_get == we_expect)
01199 return;
01200
01201
01202
01203 if (! (we_get & MEANTWI)) {
01204 ps.outimage = vircam_dummy_image(ps.twilights[0]);
01205 vircam_twilight_flat_combine_config.flatrms = 0.0;
01206 }
01207
01208
01209
01210 if (! (we_get & CONFMAP)) {
01211 ps.outconf = vircam_dummy_image(ps.twilights[0]);
01212 vircam_twilight_flat_combine_config.flatrms = 0.0;
01213 }
01214
01215
01216
01217 if ((we_expect & RATIMG) && ! (we_get & RATIMG)) {
01218 vircam_twilight_flat_combine_config.flatratio_med = 0.0;
01219 vircam_twilight_flat_combine_config.flatratio_rms = 0.0;
01220 ps.ratioimg = vircam_dummy_image(ps.twilights[0]);
01221 }
01222
01223
01224
01225 if ((we_expect & STATS_TAB) && ! (we_get & STATS_TAB))
01226 ps.ratioimstats = vircam_create_diffimg_stats(0);
01227
01228 return;
01229 }
01230
01231
01236
01237
01238 static void vircam_twilight_flat_combine_normal(int jext) {
01239 int nx,ny,ncells,status;
01240 long i,npi;
01241 unsigned char *bpm;
01242 float *idata,med,sig,gdiff,grms;
01243 const char *fctid="vircam_twilight_flat_combine_normal";
01244
01245
01246
01247 nx = (int)cpl_image_get_size_x(ps.outimage);
01248 ny = (int)cpl_image_get_size_y(ps.outimage);
01249 npi = nx*ny;
01250 vircam_mask_load(ps.master_mask,jext,nx,ny);
01251 bpm = vircam_mask_get_data(ps.master_mask);
01252
01253
01254
01255 status = VIR_OK;
01256 (void)vircam_mkconf(ps.outimage,(char *)"None Available",ps.master_mask,
01257 &(ps.outconf),&(ps.drs2),&status);
01258 if (status == VIR_OK)
01259 we_get |= CONFMAP;
01260 else {
01261 cpl_msg_info(fctid,
01262 "Confidence map creation failed extension %" CPL_SIZE_FORMAT,
01263 (cpl_size)jext);
01264 status = VIR_OK;
01265 }
01266
01267
01268
01269 idata = cpl_image_get_data(ps.outimage);
01270 vircam_medsig(idata,bpm,npi,&med,&sig);
01271
01272
01273
01274 for (i = 0; i < npi; i++)
01275 if (bpm[i])
01276 idata[i] = med;
01277
01278
01279
01280 cpl_propertylist_update_float(ps.drs,"ESO DRS MEDFLAT",med);
01281 cpl_propertylist_set_comment(ps.drs,"ESO DRS MEDFLAT",
01282 "Median value before normalisation");
01283 cpl_image_divide_scalar(ps.outimage,med);
01284 vircam_medmad(idata,bpm,npi,&med,&sig);
01285 sig *= 1.48;
01286 vircam_twilight_flat_combine_config.flatrms = sig;
01287
01288
01289
01290 if (ps.master_twilight_flat != NULL) {
01291 ps.mfimage = vircam_fits_load(ps.master_twilight_flat,CPL_TYPE_FLOAT,jext);
01292 if (ps.mfimage == NULL) {
01293 cpl_msg_info(fctid,
01294 "Master twilight extension %" CPL_SIZE_FORMAT " won't load",
01295 (cpl_size)jext);
01296 } else if (vircam_is_dummy(vircam_fits_get_ehu(ps.mfimage))) {
01297 cpl_msg_info(fctid,
01298 "Master twilight extension %" CPL_SIZE_FORMAT " is a dummy",
01299 (cpl_size)jext);
01300 freefits(ps.mfimage);
01301 }
01302 } else
01303 ps.mfimage = NULL;
01304
01305
01306
01307
01308
01309
01310
01311
01312 vircam_twilight_flat_combine_config.flatratio_med = 0.0;
01313 vircam_twilight_flat_combine_config.flatratio_rms = 0.0;
01314 ncells = vircam_twilight_flat_combine_config.ncells;
01315 vircam_difference_image(vircam_fits_get_image(ps.mfimage),ps.outimage,bpm,
01316 vircam_tfits_get_table(ps.ctable),ncells,2,
01317 &gdiff,&grms,&(ps.ratioimg),
01318 &(ps.ratioimstats));
01319 vircam_mask_clear(ps.master_mask);
01320 vircam_twilight_flat_combine_config.flatratio_med = gdiff;
01321 vircam_twilight_flat_combine_config.flatratio_rms = grms;
01322 if (ps.ratioimg != NULL)
01323 we_get |= RATIMG;
01324 if (ps.ratioimstats != NULL)
01325 we_get |= STATS_TAB;
01326 return;
01327 }
01328
01329
01337
01338
01339
01340 static int vircam_twilight_flat_combine_lastbit(int jext,
01341 cpl_frameset *framelist,
01342 cpl_parameterlist *parlist) {
01343 int retval;
01344 const char *fctid="vircam_twilight_flat_combine_lastbit";
01345
01346
01347
01348 vircam_twilight_flat_combine_dummy_products();
01349
01350
01351
01352 cpl_msg_info(fctid,
01353 "Saving products for extension %" CPL_SIZE_FORMAT,
01354 (cpl_size)jext);
01355 retval = vircam_twilight_flat_combine_save(framelist,parlist);
01356 if (retval != 0) {
01357 vircam_twilight_flat_combine_tidy(2);
01358 return(-1);
01359 }
01360
01361
01362
01363 vircam_twilight_flat_combine_tidy(1);
01364 return(0);
01365 }
01366
01367
01371
01372
01373 static void vircam_twilight_flat_combine_init(void) {
01374 ps.labels = NULL;
01375 ps.twilightlist = NULL;
01376 ps.twilights = NULL;
01377 ps.good = NULL;
01378 ps.master_dark = NULL;
01379 ps.master_twilight_flat = NULL;
01380 ps.master_mask = NULL;
01381 ps.chantab = NULL;
01382 ps.ctable = NULL;
01383 ps.outimage = NULL;
01384 ps.outconf = NULL;
01385 ps.drs = NULL;
01386 ps.drs2 = NULL;
01387 ps.rejmask = NULL;
01388 ps.rejplus = NULL;
01389 ps.mfimage = NULL;
01390 ps.ratioimg = NULL;
01391 ps.ratioimstats = NULL;
01392 ps.phupaf = NULL;
01393 }
01394
01395
01399
01400
01401 static void vircam_twilight_flat_combine_tidy(int level) {
01402 freeimage(ps.outimage);
01403 freeimage(ps.outconf);
01404 freefitslist(ps.twilights,ps.ntwilights);
01405 freepropertylist(ps.drs);
01406 freepropertylist(ps.drs2);
01407 freespace(ps.rejmask);
01408 freespace(ps.rejplus);
01409 freefits(ps.mfimage);
01410 freeimage(ps.ratioimg);
01411 freetable(ps.ratioimstats);
01412 freetfits(ps.ctable);
01413 freefits(ps.mdark);
01414 if (level == 1)
01415 return;
01416
01417 freespace(ps.good);
01418 freespace(ps.labels);
01419 freeframeset(ps.twilightlist);
01420 freeframe(ps.master_dark);
01421 freeframe(ps.master_twilight_flat);
01422 freemask(ps.master_mask);
01423 freeframe(ps.chantab);
01424 freepropertylist(ps.phupaf);
01425 }
01426
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612