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 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032 #include <fors_img_screen_flat_impl.h>
00033
00034 #include <fors_stack.h>
00035 #include <fors_tools.h>
00036 #include <fors_dfs.h>
00037 #include <fors_qc.h>
00038 #include <fors_utils.h>
00039
00040 #include <cpl.h>
00041 #include <math.h>
00042
00049 const char *const fors_img_screen_flat_name = "fors_img_screen_flat";
00050 const char *const fors_img_screen_flat_description_short =
00051 "Compute master screen flat frame";
00052 const char *const fors_img_screen_flat_author = "Jonas M. Larsen";
00053 const char *const fors_img_screen_flat_email = PACKAGE_BUGREPORT;
00054 const char *const fors_img_screen_flat_description =
00055 "After bias subtraction, the input flat field frames are combined using\n"
00056 "the given stack method. The combined frame is finally normalised dividing\n"
00057 "it by its large scale illumination trend. The large scale trend is obtained\n"
00058 "by applying a median filter with a large kernel. To avoid boundary effects, \n"
00059 "the median filter is applied only to the specified region.\n"
00060 "The overscan regions, if present, are removed from the result.\n\n"
00061 "Input files:\n"
00062 "\n"
00063 " DO category: Type: Explanation: Required:\n"
00064 " SCREEN_FLAT_IMG Raw Screen flat field Y\n"
00065 " MASTER_BIAS Raw Master bias Y\n"
00066 "\n"
00067 "Output files:\n\n"
00068 " DO category: Data type: Explanation:\n"
00069 " MASTER_SCREEN_FLAT_IMG FITS image Master screen flat field\n";
00070
00071
00072 static void
00073 remove_large_scale(fors_image *master_screen_flat,
00074 const cpl_parameterlist *parameters,
00075 const char *context,
00076 const fors_setting *setting);
00077
00078 static void
00079 remove_large_scale_fit(fors_image *master_screen_flat,
00080 const cpl_parameterlist *parameters,
00081 const char *context,
00082 const fors_setting *setting);
00083
00084 static void
00085 write_qc(cpl_propertylist *qc,
00086 const cpl_frame *first_raw,
00087 const fors_image_list *sflats,
00088 const fors_image *master_sflat,
00089 const fors_setting *setting,
00090 double saturation);
00096 void fors_img_screen_flat_define_parameters(cpl_parameterlist *parameters)
00097 {
00098 const char *context = cpl_sprintf("fors.%s", fors_img_screen_flat_name);
00099 const char *full_name = NULL;
00100
00101 fors_stack_define_parameters(parameters, context, "average");
00102
00103 {
00104 cpl_parameter *p;
00105 const char *name;
00106
00107
00108 name = "xradius";
00109 full_name = cpl_sprintf("%s.%s", context, name);
00110 p = cpl_parameter_new_value(full_name,
00111 CPL_TYPE_INT,
00112 "Median filter x radius (unbinned pixels)",
00113 context,
00114 50);
00115 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00116 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00117 cpl_parameterlist_append(parameters, p);
00118 cpl_free((void *)full_name); full_name = NULL;
00119
00120 name = "yradius";
00121 full_name = cpl_sprintf("%s.%s", context, name);
00122 p = cpl_parameter_new_value(full_name,
00123 CPL_TYPE_INT,
00124 "Median filter y radius (unbinned pixels)",
00125 context,
00126 50);
00127 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00128 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00129 cpl_parameterlist_append(parameters, p);
00130 cpl_free((void *)full_name); full_name = NULL;
00131
00132 name = "degree";
00133 full_name = cpl_sprintf("%s.%s", context, name);
00134 p = cpl_parameter_new_value(full_name,
00135 CPL_TYPE_INT,
00136 "Degree of fitting polynomial",
00137 context,
00138 -1);
00139 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00140 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00141 cpl_parameterlist_append(parameters, p);
00142 cpl_free((void *)full_name); full_name = NULL;
00143
00144 name = "sampling";
00145 full_name = cpl_sprintf("%s.%s", context, name);
00146 p = cpl_parameter_new_value(full_name,
00147 CPL_TYPE_INT,
00148 "Sampling interval for fitting",
00149 context,
00150 100);
00151 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
00152 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00153 cpl_parameterlist_append(parameters, p);
00154 cpl_free((void *)full_name); full_name = NULL;
00155 }
00156
00157 cpl_free((void *)context);
00158 cpl_free((void *)full_name);
00159
00160 return;
00161 }
00162
00163 #undef cleanup
00164 #define cleanup \
00165 do { \
00166 cpl_frameset_delete(sflat_frames); \
00167 fors_setting_delete(&setting); \
00168 cpl_frameset_delete(master_bias_frame); \
00169 fors_image_delete_const(&master_bias); \
00170 fors_stack_method_delete(&sm); \
00171 cpl_free((void *)context); \
00172 fors_image_delete(&master_screen_flat); \
00173 fors_image_delete(&master_norm_flat); \
00174 fors_image_list_delete_const(&sflats, fors_image_delete); \
00175 cpl_propertylist_delete(qc); \
00176 } while (0)
00177
00185 void
00186 fors_img_screen_flat(cpl_frameset *frames, const cpl_parameterlist *parameters)
00187 {
00188
00189 cpl_frameset *sflat_frames = NULL;
00190 const fors_image_list *sflats = NULL;
00191 fors_setting *setting = NULL;
00192
00193
00194 cpl_frameset *master_bias_frame = NULL;
00195 const fors_image *master_bias = NULL;
00196
00197
00198 fors_image *master_screen_flat = NULL;
00199 fors_image *master_norm_flat = NULL;
00200
00201
00202 cpl_propertylist *qc = cpl_propertylist_new();
00203 double saturation;
00204
00205
00206 stack_method *sm = NULL;
00207
00208
00209 const char *context = cpl_sprintf("fors.%s", fors_img_screen_flat_name);
00210
00211
00212 sm = fors_stack_method_new(parameters, context);
00213 assure( !cpl_error_get_code(), return, "Could not get stacking method");
00214
00215
00216 sflat_frames = fors_frameset_extract(frames, SCREEN_FLAT_IMG);
00217 assure( cpl_frameset_get_size(sflat_frames) > 0, return,
00218 "No %s provided", SCREEN_FLAT_IMG);
00219
00220
00221 master_bias_frame = fors_frameset_extract(frames, MASTER_BIAS);
00222 assure( cpl_frameset_get_size(master_bias_frame) == 1, return,
00223 "One %s required. %d found",
00224 MASTER_BIAS, cpl_frameset_get_size(master_bias_frame));
00225
00226
00227 setting = fors_setting_new(cpl_frameset_get_first(sflat_frames));
00228 assure( !cpl_error_get_code(), return, "Could not get instrument setting" );
00229
00230 master_bias = fors_image_load(cpl_frameset_get_first(master_bias_frame),
00231 NULL, setting, NULL);
00232 assure( !cpl_error_get_code(), return,
00233 "Could not load master bias");
00234
00235
00236 sflats = fors_image_load_list_const(sflat_frames, master_bias,
00237 setting, &saturation);
00238 assure( !cpl_error_get_code(), return, "Could not load screen flat images");
00239
00240
00241 master_screen_flat = fors_stack_const(sflats, sm);
00242 assure( !cpl_error_get_code(), return, "Screen flat stacking failed");
00243
00244
00245 master_norm_flat = fors_image_duplicate(master_screen_flat);
00246 remove_large_scale(master_norm_flat,
00247 parameters, context,
00248 setting);
00249
00250 assure( !cpl_error_get_code(), return,
00251 "Flat field smoothing/normalization failed");
00252
00253
00254 write_qc(qc, cpl_frameset_get_first(sflat_frames),
00255 sflats, master_norm_flat, setting, saturation);
00256 assure( !cpl_error_get_code(), return, "Failed to compute QC");
00257
00258
00259 fors_dfs_save_image(frames, master_screen_flat, MASTER_SCREEN_FLAT_IMG,
00260 NULL, parameters, fors_img_screen_flat_name,
00261 cpl_frameset_get_first(sflat_frames));
00262 assure( !cpl_error_get_code(), return, "Saving %s failed",
00263 MASTER_SCREEN_FLAT_IMG);
00264
00265 fors_dfs_save_image(frames, master_norm_flat, MASTER_NORM_FLAT_IMG,
00266 qc, parameters, fors_img_screen_flat_name,
00267 cpl_frameset_get_first(sflat_frames));
00268 assure( !cpl_error_get_code(), return, "Saving %s failed",
00269 MASTER_NORM_FLAT_IMG);
00270
00271 cleanup;
00272 return;
00273 }
00274
00275 #undef cleanup
00276 #define cleanup \
00277 do { \
00278 cpl_image_delete(smoothed); \
00279 } while (0)
00280
00298 static void
00299 remove_large_scale(fors_image *master_screen_flat,
00300 const cpl_parameterlist *parameters,
00301 const char *context,
00302 const fors_setting *setting)
00303
00304 {
00305 cpl_image *smoothed = NULL;
00306 const char *name;
00307 int xradius, yradius;
00308 int xstart, ystart;
00309 int xend, yend;
00310
00311 name = cpl_sprintf("%s.%s", context, "degree");
00312 const cpl_parameter *param = cpl_parameterlist_find_const(parameters, name);
00313 int degree = cpl_parameter_get_int(param);
00314 cpl_free((void *)name); name = NULL;
00315 if (degree >= 0) {
00316 remove_large_scale_fit(master_screen_flat, parameters, context,
00317 setting);
00318 return;
00319 }
00320
00321 cpl_msg_info(cpl_func, "Median filter parameters:");
00322
00323 cpl_msg_indent_more();
00324 cpl_msg_indent_more();
00325 name = cpl_sprintf("%s.%s", context, "xradius");
00326 xradius = dfs_get_parameter_int_const(parameters,
00327 name);
00328 cpl_free((void *)name); name = NULL;
00329 cpl_msg_indent_less();
00330 cpl_msg_indent_less();
00331 assure( !cpl_error_get_code(), return, NULL );
00332
00333
00334 cpl_msg_indent_more();
00335 cpl_msg_indent_more();
00336 name = cpl_sprintf("%s.%s", context, "yradius");
00337 yradius = dfs_get_parameter_int_const(parameters,
00338 name);
00339 cpl_free((void *)name); name = NULL;
00340 cpl_msg_indent_less();
00341 cpl_msg_indent_less();
00342 assure( !cpl_error_get_code(), return, NULL );
00343
00344
00345 bool use_data = true;
00346
00347
00348 xradius = (xradius - 1)/setting->binx + 1;
00349 yradius = (yradius - 1)/setting->biny + 1;
00350 xstart = 1;
00351 ystart = 1;
00352 xend = fors_image_get_size_x(master_screen_flat);
00353 yend = fors_image_get_size_y(master_screen_flat);
00354 int xstep = 1;
00355 int ystep = 1;
00356
00357 smoothed = fors_image_filter_median_create(master_screen_flat,
00358 xradius, yradius,
00359 xstart, ystart,
00360 xend, yend,
00361 xstep, ystep,
00362 use_data);
00363
00364 assure( !cpl_error_get_code(), return, NULL );
00365
00366 int DEBUG = 1;
00367 if (DEBUG) {
00368 const char *filename = "smooth.fits";
00369
00370 cpl_msg_info(cpl_func, "Saving large scale structure image to %s",
00371 filename);
00372 cpl_image_save(smoothed, filename, CPL_BPP_IEEE_FLOAT,
00373 NULL, CPL_IO_DEFAULT);
00374 }
00375
00376 fors_image_divide_noerr(master_screen_flat, smoothed);
00377
00378
00379 cleanup;
00380 return;
00381 }
00382
00383
00384
00385 #undef cleanup
00386 #define cleanup \
00387 do { \
00388 cpl_image_delete(smoothed); \
00389 } while (0)
00390
00406 static void
00407 remove_large_scale_fit(fors_image *master_screen_flat,
00408 const cpl_parameterlist *parameters,
00409 const char *context,
00410 const fors_setting *setting)
00411
00412 {
00413 cpl_image *smoothed = NULL;
00414 const char *name;
00415 int step;
00416 int degree;
00417
00418 cpl_msg_info(cpl_func, "Large scale fitting parameters:");
00419
00420 cpl_msg_indent_more();
00421 cpl_msg_indent_more();
00422 name = cpl_sprintf("%s.%s", context, "sampling");
00423 step = dfs_get_parameter_int_const(parameters,
00424 name);
00425 cpl_free((void *)name); name = NULL;
00426 cpl_msg_indent_less();
00427 cpl_msg_indent_less();
00428 assure( !cpl_error_get_code(), return, NULL );
00429
00430 cpl_msg_indent_more();
00431 cpl_msg_indent_more();
00432 name = cpl_sprintf("%s.%s", context, "degree");
00433 degree = dfs_get_parameter_int_const(parameters,
00434 name);
00435 cpl_free((void *)name); name = NULL;
00436 cpl_msg_indent_less();
00437 cpl_msg_indent_less();
00438 assure( !cpl_error_get_code(), return, NULL );
00439
00440
00441
00442
00443
00444
00445 float level = fors_image_get_median(master_screen_flat, NULL) / 2;
00446
00447 smoothed = fors_image_flat_fit_create(master_screen_flat,
00448 step, degree, level);
00449
00450 assure( !cpl_error_get_code(), return, NULL );
00451
00452 int DEBUG = 1;
00453 if (DEBUG) {
00454 const char *filename = "smooth.fits";
00455
00456 cpl_msg_info(cpl_func, "Saving large scale structure image to %s",
00457 filename);
00458 cpl_image_save(smoothed, filename, CPL_BPP_IEEE_FLOAT,
00459 NULL, CPL_IO_DEFAULT);
00460 }
00461
00462 fors_image_divide_noerr(master_screen_flat, smoothed);
00463
00464
00465 cleanup;
00466 return;
00467 }
00468
00469
00470
00471 #undef cleanup
00472 #define cleanup \
00473 do { \
00474 fors_image_delete(&image); \
00475 } while (0)
00476
00484 static void
00485 write_qc(cpl_propertylist *qc,
00486 const cpl_frame *first_raw_frame,
00487 const fors_image_list *sflats,
00488 const fors_image *master_sflat,
00489 const fors_setting *setting,
00490 double saturation)
00491 {
00492 fors_image *image = NULL;
00493
00494 fors_qc_start_group(qc, fors_qc_dic_version, setting->instrument);
00495
00496 fors_qc_write_group_heading(first_raw_frame,
00497 MASTER_SCREEN_FLAT_IMG,
00498 setting->instrument);
00499 assure( !cpl_error_get_code(), return, "Could not write %s QC parameters",
00500 MASTER_SCREEN_FLAT_IMG);
00501
00502
00503
00504 fors_qc_write_qc_double(qc,
00505 saturation,
00506 "QC.OVEREXPO",
00507 "%",
00508 "Percentage of overexposed pixels",
00509 setting->instrument);
00510
00511
00512
00513
00514
00515 const fors_image *first_raw = fors_image_list_first_const(sflats);
00516 const fors_image *second_raw = fors_image_list_next_const(sflats);
00517
00518 fors_qc_write_qc_double(qc,
00519
00520 fors_image_get_median(first_raw, NULL)
00521 / setting->exposure_time,
00522 "QC.FLAT.EFF",
00523 "ADU/s",
00524 "Flat field lamp efficiency",
00525 setting->instrument);
00526
00527
00528
00529
00530
00531
00532 double master_photon_noise;
00533 double conad, conad_err;
00534
00535
00536
00537
00538
00539
00540
00541 if (second_raw != NULL) {
00542
00543
00544
00545
00546
00547 if (fors_image_get_size_x(second_raw) >= 101 &&
00548 fors_image_get_size_y(second_raw) >= 101) {
00549
00550 fors_image *center_first = fors_image_duplicate(first_raw);
00551 fors_image *center_second = fors_image_duplicate(second_raw);
00552
00553 int mid_x = (fors_image_get_size_x(center_first) + 1) / 2;
00554 int mid_y = (fors_image_get_size_y(center_first) + 1) / 2;
00555
00556 fors_image_crop(center_first,
00557 mid_x - 50, mid_y - 50,
00558 mid_x + 50, mid_y + 50);
00559
00560 fors_image_crop(center_second,
00561 mid_x - 50, mid_y - 50,
00562 mid_x + 50, mid_y + 50);
00563
00564
00565
00566
00567
00568
00569 image = fors_image_duplicate(center_first);
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 fors_image *ratio = fors_image_duplicate(center_first);
00587 fors_image_divide(ratio, center_second);
00588 double k = fors_image_get_median(ratio, NULL);
00589 fors_image_delete(&ratio);
00590
00591
00592 fors_image_multiply_scalar(center_second, k, -1);
00593 fors_image_subtract(center_first, center_second);
00594 fors_image_delete(¢er_second);
00595
00596
00597 master_photon_noise = fors_image_get_stdev(center_first, NULL);
00598 master_photon_noise /= sqrt(1+k);
00599
00600
00601
00602
00603
00604
00605 master_photon_noise /= sqrt(fors_image_list_size(sflats));
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 fors_image_square(center_first);
00621 fors_image_divide(center_first, image);
00622
00623
00624
00625
00626
00627
00628
00629 double gain = fors_image_get_mean(center_first, NULL) / (1+k);
00630 double gain_err = fors_image_get_stdev(center_first, NULL) / (1+k);
00631 fors_image_delete(¢er_first);
00632 fors_image_delete(&image);
00633
00634
00635
00636
00637
00638 conad = 1.0 / gain;
00639 conad_err = conad * gain_err/gain;
00640 conad_err /= 101;
00641 }
00642 else {
00643 cpl_msg_warning(cpl_func,
00644 "Raw images too small (%dx%d), "
00645 "need size 101x101 to compute master flat "
00646 "photon noise and gain",
00647 fors_image_get_size_x(second_raw),
00648 fors_image_get_size_y(second_raw));
00649
00650 master_photon_noise = -1;
00651 }
00652 }
00653 else {
00654 cpl_msg_warning(cpl_func, "Only 1 raw frame provided, "
00655 "cannot compute master flat photon noise");
00656 master_photon_noise = -1;
00657 }
00658
00659 fors_qc_write_qc_double(qc,
00660 master_photon_noise,
00661 "QC.FLAT.PHN",
00662 "ADU",
00663 "Photon noise in master screen flat field",
00664 setting->instrument);
00665
00666 double master_fixed_pattern_noise =
00667 fors_fixed_pattern_noise(master_sflat,
00668 fors_image_get_median(first_raw, NULL),
00669 master_photon_noise);
00670 assure( !cpl_error_get_code(), return,
00671 "Could not compute fixed pattern noise" );
00672
00673 fors_qc_write_qc_double(qc,
00674 master_fixed_pattern_noise,
00675 "QC.FLAT.FPN",
00676 "ADU",
00677 "Fixed-pattern noise",
00678 setting->instrument);
00679
00680 master_fixed_pattern_noise /= fors_image_get_median(first_raw, NULL);
00681
00682 fors_qc_write_qc_double(qc,
00683 master_fixed_pattern_noise,
00684 "QC.FLAT.FPN.REL",
00685 NULL,
00686 "Relative fixed-pattern noise",
00687 setting->instrument);
00688
00689 fors_qc_write_qc_double(qc,
00690 conad,
00691 "QC.FLAT.CONAD",
00692 "e-/ADU",
00693 "Conversion factor from ADU to electrons",
00694 setting->instrument);
00695
00696 fors_qc_write_qc_double(qc,
00697 conad_err,
00698 "QC.FLAT.CONADERR",
00699 "e-/ADU",
00700 "Error on conversion factor ADU/electrons",
00701 setting->instrument);
00702
00703 #define SALTA 1
00704 #ifndef SALTA
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 double conad, conad_err;
00720
00721 if (second_raw != NULL) {
00722 image = fors_image_duplicate(first_raw);
00723 fors_image_subtract(image, second_raw);
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 double gain_mean, gain_err;
00734
00735 {
00736 double first_raw_median = fors_image_get_median(first_raw, NULL);
00737
00738 const float *first_raw_data = fors_image_get_data_const(first_raw);
00739 const float *diff_data = fors_image_get_data_const(image);
00740
00741 const int Ntot = fors_image_get_size_x(image)
00742 * fors_image_get_size_y(image);
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 double diff_mean = 0;
00759 int N = 0;
00760 int i;
00761 for (i = 0; i < Ntot; i++) {
00762 if (first_raw_data[i] > 0.5 * first_raw_median) {
00763 diff_mean += diff_data[i];
00764 N += 1;
00765 }
00766 }
00767 diff_mean /= N;
00768 fors_image_subtract_scalar(image, diff_mean, -1);
00769
00770
00771
00772
00773
00774 fors_image_square(image);
00775 fors_image_divide_scalar(image, 2, -1);
00776
00777
00778
00779
00780
00781
00782 double sum_vf = 0;
00783 double sum_vfvf = 0;
00784 N = 0;
00785 for (i = 0; i < Ntot; i++) {
00786 if (first_raw_data[i] > 0.5 * first_raw_median) {
00787 double vf = diff_data[i] / first_raw_data[i];
00788 sum_vf += vf;
00789 sum_vfvf += vf*vf;
00790 N += 1;
00791 }
00792 }
00793
00794 gain_mean = sum_vf / N;
00795 double vfvf_mean = sum_vfvf / N;
00796 gain_err = sqrt(fabs(vfvf_mean - gain_mean*gain_mean));
00797
00798
00799
00800
00801
00802
00803 double hicut = gain_mean + 5*gain_err;
00804 sum_vf = 0;
00805 sum_vfvf = 0;
00806 N = 0;
00807 for (i = 0; i < Ntot; i++) {
00808 if (first_raw_data[i] > 0.5 * first_raw_median) {
00809 double vf = diff_data[i] / first_raw_data[i];
00810 if (vf < hicut) {
00811 sum_vf += vf;
00812 sum_vfvf += vf*vf;
00813 N += 1;
00814 }
00815 }
00816 }
00817
00818 cpl_msg_info(cpl_func, "Using %d of %d pixels for gain estimation",
00819 N, Ntot);
00820
00821 gain_mean = sum_vf / N;
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 vfvf_mean = sum_vfvf / N;
00834
00835 gain_err = sqrt(fabs(vfvf_mean - gain_mean*gain_mean));
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846 gain_err /= sqrt(N);
00847 }
00848
00849 assure( gain_mean > 0, return,
00850 "Difference between first two raw input frames is "
00851 "always zero, cannot estimate gain");
00852
00853 conad = 1.0/gain_mean;
00854
00855
00856
00857
00858
00859 conad_err = conad * gain_err/gain_mean;
00860 }
00861 else {
00862 cpl_msg_warning(cpl_func, "Only 1 raw frame provided, "
00863 "cannot estimate CONAD");
00864 conad = -1;
00865 conad_err = -1;
00866 }
00867
00868 fors_qc_write_qc_double(qc,
00869 conad,
00870 "QC.FLAT.CONAD",
00871 "e-/ADU",
00872 "Conversion factor from ADU to electrons",
00873 setting->instrument);
00874
00875 fors_qc_write_qc_double(qc,
00876 conad_err,
00877 "QC.FLAT.CONADERR",
00878 "e-/ADU",
00879 "Error on conversion factor ADU/electrons",
00880 setting->instrument);
00881 #endif
00882
00883 fors_qc_end_group();
00884
00885 cleanup;
00886 return;
00887 }
00888
00889