38 #include "midi_utils.h"
39 #include "midi_pfits.h"
41 #include "midiControl.h"
42 #include "midiGlobal.h"
43 #include "midiAppendPropertylist.h"
45 #include "midi_cplupgrade.h"
51 static int midi_acq_create(cpl_plugin *) ;
52 static int midi_acq_exec(cpl_plugin *) ;
53 static int midi_acq_destroy(cpl_plugin *) ;
54 static int midi_acq(cpl_parameterlist *, cpl_frameset *) ;
55 static int table_to_imglst(
const char * columname,
56 const char * columntype,
57 cpl_imagelist * imglst_target,
58 const char * columnentry,
60 static cpl_error_code midi_qc_acq(
const cpl_image * image,
61 cpl_propertylist * pro_list);
62 static cpl_error_code midi_image_get_fwhm(
68 static double midi_vector_get_fwhm(
69 const cpl_vector * vec,
72 static int midi_isnan(
double value);
79 static char midi_acq_description[] =
80 "The purpose of this recipe is to assess the position, size and the flux\n"
81 "intensity of the target.\n\n"
83 " DO category: Type: Explanation: Required:\n"
84 " ACQ Raw Raw data frame Y\n\n"
86 " DO category: Data type: Explanation:\n"
87 " IMAGE_QUALITY FITS image Image of the beam\n\n";
105 cpl_recipe * recipe = cpl_calloc(1,
sizeof *recipe ) ;
106 cpl_plugin * plugin = &recipe->interface ;
108 cpl_plugin_init(plugin,
111 CPL_PLUGIN_TYPE_RECIPE,
113 "Image quality assessment",
114 midi_acq_description,
122 cpl_pluginlist_append(list, plugin) ;
136 static int midi_acq_create(cpl_plugin * plugin)
138 cpl_recipe * recipe ;
142 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
143 recipe = (cpl_recipe *)plugin ;
147 recipe->parameters = cpl_parameterlist_new() ;
161 static int midi_acq_exec(cpl_plugin * plugin)
163 cpl_recipe * recipe ;
166 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
167 recipe = (cpl_recipe *)plugin ;
171 return midi_acq(recipe->parameters, recipe->frames) ;
181 static int midi_acq_destroy(cpl_plugin * plugin)
183 cpl_recipe * recipe ;
186 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
187 recipe = (cpl_recipe *)plugin ;
190 cpl_parameterlist_delete(recipe->parameters) ;
203 cpl_parameterlist *parlist,
204 cpl_frameset *frameset)
207 cpl_frame * current_frame;
211 cpl_propertylist * header=NULL;
213 cpl_frame * cur_frame=NULL;
214 cpl_table * table=NULL;
215 cpl_imagelist * imglst_data1;
216 cpl_imagelist * imglst_data2;
217 cpl_image * image_data1, * image_data2;
218 cpl_image * image_data1_mask, * image_data2_mask;
219 cpl_mask * mask_data1, * mask_data2;
221 cpl_errorstate prestate = cpl_errorstate_get();
222 int ext_imaging_data=0;
223 double median_data1, median_data2;
224 cpl_propertylist * qclist_data1=NULL;
225 cpl_propertylist * qclist_data2=NULL;
226 char station[]=
"AT";
229 current_frame = cpl_frameset_get_first(frameset);
230 sofPtr = fopen (
"MIDI_sof.log",
"w");
231 while ( current_frame && sofPtr )
233 fprintf (sofPtr,
"%s \n", (
char *)cpl_frame_get_filename(current_frame));
234 current_frame = cpl_frameset_get_next( frameset );
239 executeDataReduction (
"",
"",
"./", plotDuration,
"MIDI_sof.log",&error,
241 if (error)
return -1;
242 remove (
"MIDI_sof.log");
244 if (CPL_ERROR_NONE != appendPropertylist(
"MIDI_b1_acq_DATA1.pro.fits",
245 CPL_FRAME_TYPE_IMAGE,
"IMAGE_QUALITY",frameset,parlist))
247 cpl_msg_error(cpl_func,
"Error in appendPropertylist");
250 if (CPL_ERROR_NONE != appendPropertylist(
"MIDI_b1_acq_DATA2.pro.fits",
251 CPL_FRAME_TYPE_IMAGE,
"IMAGE_QUALITY",frameset,parlist))
253 cpl_msg_error(cpl_func,
"Error in appendPropertylist");
261 imglst_data1=cpl_imagelist_new();
262 imglst_data2=cpl_imagelist_new();
265 cur_frame=cpl_frameset_find(frameset,MIDI_ACQ);
266 if (cur_frame == NULL) {
267 return (
int)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
268 "SOF does not have any file");
272 cpl_msg_info(cpl_func,
"Processing file %s",
273 cpl_frame_get_filename(cur_frame));
275 header = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
279 strcpy(station,
"AT");
281 if (cpl_propertylist_has(header,
"ESO ISS CONF STATION1") == 1)
283 if(strcmp(cpl_propertylist_get_string(header,
284 "ESO ISS CONF STATION1"),
"U1")==0 ||
285 strcmp(cpl_propertylist_get_string(header,
286 "ESO ISS CONF STATION1"),
"U2")==0 ||
287 strcmp(cpl_propertylist_get_string(header,
288 "ESO ISS CONF STATION1"),
"U3")==0 ||
289 strcmp(cpl_propertylist_get_string(header,
290 "ESO ISS CONF STATION1"),
"U4")==0){
291 strcpy(station,
"UT");
297 ext_imaging_data=cpl_fits_find_extension(cpl_frame_get_filename(cur_frame),
299 table =cpl_table_load(cpl_frame_get_filename(cur_frame),ext_imaging_data,1);
301 cpl_imagelist_delete(imglst_data1);
302 cpl_imagelist_delete(imglst_data2);
303 cpl_propertylist_delete(header);
304 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
305 "Could not load the table");
307 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
309 cpl_msg_indent_more();
310 cpl_msg_info(cpl_func,
"Reading DATA1 and DATA2 frames into imagelists ...");
312 if (cpl_table_has_column(table,
"DATA1")){
313 table_to_imglst(
"DATA1",
"TARTYP1",imglst_data1,
"S",table);
314 table_to_imglst(
"DATA1",
"TARTYP1",imglst_data1,
"T",table);
316 if (cpl_table_has_column(table,
"DATA2")){
317 table_to_imglst(
"DATA2",
"TARTYP2",imglst_data2,
"S",table);
318 table_to_imglst(
"DATA2",
"TARTYP2",imglst_data2,
"T",table);
322 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
323 cpl_msg_info(cpl_func,
"Processed DATA1 frames: % " CPL_SIZE_FORMAT
"",
324 cpl_imagelist_get_size(imglst_data1));
325 cpl_msg_info(cpl_func,
"Processed DATA2 frames: % " CPL_SIZE_FORMAT
"",
326 cpl_imagelist_get_size(imglst_data2));
327 cpl_imagelist_save(imglst_data1,
"imglst_data1.fits", CPL_BPP_IEEE_FLOAT,
328 NULL, CPL_IO_CREATE);
329 cpl_imagelist_save(imglst_data2,
"imglst_data2.fits", CPL_BPP_IEEE_FLOAT,
330 NULL, CPL_IO_CREATE);
333 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
334 cpl_table_delete(table);
338 cpl_msg_info(cpl_func,
"Averaging the imagelists ...");
339 image_data1=cpl_imagelist_collapse_create(imglst_data1);
340 image_data2=cpl_imagelist_collapse_create(imglst_data2);
342 cpl_msg_info(cpl_func,
"Calculating the median ...");
343 median_data1=cpl_image_get_median(image_data1);
344 median_data2=cpl_image_get_median(image_data2);
345 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
346 cpl_msg_info(cpl_func,
"First median DATA1: %f DATA12:%f", median_data1,
352 cpl_msg_info(cpl_func,
"Creating a mask by using the median ...");
353 mask_data1=cpl_mask_threshold_image_create(image_data1,0., median_data1);
354 cpl_image_reject_from_mask(image_data1, mask_data1) ;
355 mask_data2=cpl_mask_threshold_image_create(image_data2,0., median_data2);
356 cpl_image_reject_from_mask(image_data2, mask_data2) ;
359 cpl_msg_info(cpl_func,
"Thresholding the images by using the median ...");
360 cpl_image_threshold(image_data1,median_data1,FLT_MAX,0.,FLT_MAX);
361 cpl_image_threshold(image_data2,median_data2,FLT_MAX,0.,FLT_MAX);
363 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
364 cpl_image_save(image_data1,
"image_data1.fits", CPL_BPP_IEEE_FLOAT,
365 NULL, CPL_IO_CREATE);
366 cpl_image_save(image_data2,
"image_data2.fits", CPL_BPP_IEEE_FLOAT,
367 NULL, CPL_IO_CREATE);
373 cpl_msg_info(cpl_func,
"Re-calculating the median after thresholding ...");
374 median_data1=cpl_image_get_median(image_data1);
375 median_data2=cpl_image_get_median(image_data2);
377 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
378 cpl_msg_info(cpl_func,
"Second median DATA1: %f DATA2:%f", median_data1,
384 cpl_msg_info(cpl_func,
"Dilate the mask ...");
385 filter = cpl_matrix_new(7, 7);
386 cpl_matrix_fill(filter, 1.0);
387 cpl_mask_dilation(mask_data1, filter);
388 cpl_mask_dilation(mask_data2, filter);
389 cpl_matrix_delete(filter);
391 cpl_mask_not(mask_data1);
392 cpl_mask_not(mask_data2);
395 image_data1_mask=cpl_image_new_from_mask(mask_data1);
396 image_data2_mask=cpl_image_new_from_mask(mask_data2);
398 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
399 cpl_image_save(image_data1_mask,
"image_data1_mask.fits",
400 CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_CREATE);
401 cpl_image_save(image_data2_mask,
"image_data2_mask.fits",
402 CPL_BPP_IEEE_FLOAT, NULL, CPL_IO_CREATE);
409 cpl_msg_info(cpl_func,
"Multiply the dilated mask and the image ...");
410 cpl_image_multiply(image_data1,image_data1_mask);
411 cpl_image_multiply(image_data2,image_data2_mask);
413 cpl_msg_indent_less();
414 if (strcmp(station,
"AT")==0)
417 cpl_image_subtract_scalar(image_data1,median_data1);
418 cpl_image_subtract_scalar(image_data2,median_data2);
421 cpl_image_threshold(image_data1, (median_data1*(-1.))+1., FLT_MAX,
423 cpl_image_threshold(image_data2, (median_data2*(-1.))+1. ,FLT_MAX,
426 cpl_image_multiply_scalar(image_data1,-1.);
427 cpl_image_multiply_scalar(image_data2,-1.);
431 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
432 cpl_image_save(image_data1,
"image_data1_final.fits", CPL_BPP_IEEE_FLOAT,
433 NULL, CPL_IO_CREATE);
434 cpl_image_save(image_data2,
"image_data2_final.fits", CPL_BPP_IEEE_FLOAT,
435 NULL, CPL_IO_CREATE);
438 qclist_data1=cpl_propertylist_new();
439 qclist_data2=cpl_propertylist_new();
444 prestate = cpl_errorstate_get();
446 midi_qc_acq(image_data1,qclist_data1);
447 midi_qc_acq(image_data2,qclist_data2);
450 if (!cpl_errorstate_is_equal(prestate)) {
452 cpl_msg_warning(cpl_func,
"An error occurred! ");
453 cpl_msg_indent_more();
454 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
455 cpl_msg_indent_less();
458 cpl_msg_warning(cpl_func,
"Trying to recover ... ");
460 cpl_errorstate_set(prestate);
465 cpl_propertylist_update_string(qclist_data1, CPL_DFS_PRO_CATG,
466 "MIDI_ACQ_FOV_DATA1");
467 if (cpl_dfs_save_image(frameset, header, parlist, frameset, NULL,
468 image_data1, CPL_BPP_IEEE_FLOAT,
"midi_acq", qclist_data1, NULL,
469 PACKAGE
"/" PACKAGE_VERSION,
"midi_acq_fov_data1.fits")) {
471 (void)cpl_error_set_where(cpl_func);
474 cpl_propertylist_update_string(qclist_data2, CPL_DFS_PRO_CATG,
475 "MIDI_ACQ_FOV_DATA2");
476 if (cpl_dfs_save_image(frameset, header, parlist, frameset, NULL,
477 image_data2, CPL_BPP_IEEE_FLOAT,
"midi_acq", qclist_data2, NULL,
478 PACKAGE
"/" PACKAGE_VERSION,
"midi_acq_fov_data2.fits")) {
480 (void)cpl_error_set_where(cpl_func);
489 if (cpl_error_get_code() != CPL_ERROR_NONE) {
490 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
491 cpl_func, __LINE__, cpl_error_get_message());
493 cpl_msg_error(cpl_func,
"%s %s",cpl_error_get_message(),
494 cpl_error_get_where());
497 cpl_image_accept_all(image_data1) ;
498 cpl_mask_delete(mask_data1);
499 cpl_image_accept_all(image_data2) ;
500 cpl_mask_delete(mask_data2);
504 cpl_imagelist_delete(imglst_data1);
505 cpl_imagelist_delete(imglst_data2);
506 cpl_image_delete(image_data1);
507 cpl_image_delete(image_data2);
508 cpl_image_delete(image_data1_mask);
509 cpl_image_delete(image_data2_mask);
510 cpl_propertylist_delete(header);
511 cpl_propertylist_delete(qclist_data1);
512 cpl_propertylist_delete(qclist_data2);
520 if (cpl_error_get_code())
526 static int table_to_imglst(
const char * columname,
527 const char * columntype,
528 cpl_imagelist * imglst_target,
529 const char * columnentry,
535 cpl_array * array_data=NULL;
536 cpl_image * image_data=NULL;
537 cpl_errorstate prestate = cpl_errorstate_get();
543 dimenDATA=cpl_table_get_column_dimensions(table, columname);
544 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
545 if (dimenDATA != 2) {
546 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
547 "DATA has a wrong dimension");
552 if (cpl_table_has_column(table, columntype))
554 target_type=cpl_table_get_data_string(table, columntype);
559 return (
int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
560 "TYPE of the Column not found");
563 ctype=cpl_table_get_column_type(table, columname);
566 ctarget=cpl_imagelist_get_size(imglst_target);
568 for (i=0; i<cpl_table_get_nrow(table);i++)
571 array_data=(cpl_array *)cpl_table_get_array(table,columname, i);
572 if(ctype&CPL_TYPE_INT){
573 image_data=cpl_image_wrap_int(
574 cpl_table_get_column_dimension(table,columname,0 ),
575 cpl_table_get_column_dimension(table,columname,1 ),
576 cpl_array_get_data_int(array_data) );
578 if(ctype&CPL_TYPE_FLOAT){
579 image_data=cpl_image_wrap_float(
580 cpl_table_get_column_dimension(table,columname,0 ),
581 cpl_table_get_column_dimension(table,columname,1 ),
582 cpl_array_get_data_float(array_data) );
590 if(strcmp(target_type[i],columnentry)== 0){
591 cpl_imagelist_set(imglst_target,
592 cpl_image_cast(image_data, CPL_TYPE_FLOAT),ctarget++);
593 cpl_image_unwrap(image_data);
598 if(image_data!=NULL){
599 cpl_image_unwrap(image_data);
604 return (
int)cpl_error_get_code();
607 static cpl_error_code midi_qc_acq(
const cpl_image * image,
608 cpl_propertylist * pro_list)
611 cpl_array *parameters = NULL;
612 cpl_array *err_params = NULL;
613 cpl_array *fit_params = NULL;
614 double major=0.0,minor=0.0,angle=0.0,rms=0.0;
615 double centroid_x=0.0, centroid_y=0.0;
616 double centroid_fwhm_x=0.0, centroid_fwhm_y=0.0;
617 double gauss_x=0.0, gauss_y=0.0;
618 double gauss_sigma_x=0.0, gauss_sigma_y=0.0;
619 double gauss_fwhm_x=0.0, gauss_fwhm_y=0.0;
634 parameters = cpl_array_new(7, CPL_TYPE_DOUBLE);
635 err_params = cpl_array_new(7, CPL_TYPE_DOUBLE);
636 fit_params = cpl_array_new(7, CPL_TYPE_INT);
639 for (i = 0; i < 7; i++)
640 cpl_array_set(fit_params, i, 1);
648 if(cpl_fit_image_gaussian(image, NULL, 30, 30, 20, 20, parameters, NULL,
649 fit_params, &rms, NULL, NULL, &major, &minor, &angle, NULL)
651 !midi_isnan(cpl_array_get(parameters,0,NULL)) &&
652 !midi_isnan(cpl_array_get(parameters,1,NULL)) &&
653 !midi_isnan(cpl_array_get(parameters,2,NULL)) &&
654 !midi_isnan(cpl_array_get(parameters,3,NULL)) &&
655 !midi_isnan(cpl_array_get(parameters,4,NULL)) &&
656 !midi_isnan(cpl_array_get(parameters,5,NULL)) &&
657 !midi_isnan(cpl_array_get(parameters,6,NULL)))
661 for (i = 0; i < 7; i++){
662 cpl_msg_info(cpl_func,
"%s: %f",
663 p[i], cpl_array_get(parameters,i,NULL));
666 gauss_x=cpl_array_get(parameters,3,NULL);
667 gauss_y=cpl_array_get(parameters,4,NULL);
668 gauss_sigma_x=cpl_array_get(parameters,5,NULL);
669 gauss_sigma_y=cpl_array_get(parameters,6,NULL);
672 cpl_image_get_fwhm(image, gauss_x, gauss_y, &gauss_fwhm_x,
676 midi_image_get_fwhm(image, gauss_x, gauss_y, &gauss_fwhm_x,
680 midi_image_get_fwhm(image, gauss_x, gauss_y, &dummy, &gauss_fwhm_y);
686 centroid_x=cpl_image_get_centroid_x(image);
687 centroid_y=cpl_image_get_centroid_y(image);
689 cpl_image_get_fwhm(image, centroid_x, centroid_y, ¢roid_fwhm_x,
693 if(centroid_fwhm_x<0){
694 midi_image_get_fwhm(image, centroid_x, centroid_y, ¢roid_fwhm_x,
697 if(centroid_fwhm_y<0){
698 midi_image_get_fwhm(image, centroid_x, centroid_y, &dummy,
704 cpl_propertylist_update_float(pro_list,
705 "ESO QC GAUSS FIT X", (
float)gauss_x);
706 cpl_propertylist_update_float(pro_list,
707 "ESO QC GAUSS FIT Y", (
float)gauss_y);
708 cpl_propertylist_update_float(pro_list,
709 "ESO QC GAUSS FIT SIGMA X", (
float)gauss_sigma_x);
710 cpl_propertylist_update_float(pro_list,
711 "ESO QC GAUSS FIT SIGMA Y", (
float)gauss_sigma_y);
712 cpl_propertylist_update_float(pro_list,
713 "ESO QC GAUSS MEASURED FWHM AT X", (
float)gauss_fwhm_x);
714 cpl_propertylist_update_float(pro_list,
715 "ESO QC GAUSS MEASURED FWHM AT Y", (
float)gauss_fwhm_y);
717 cpl_propertylist_update_float(pro_list,
718 "ESO QC CENTROID X", (
float)centroid_x);
719 cpl_propertylist_update_float(pro_list,
720 "ESO QC CENTROID Y", (
float)centroid_y);
721 cpl_propertylist_update_float(pro_list,
722 "ESO QC CENTROID MEASURED FWHM AT X", (
float)centroid_fwhm_x);
723 cpl_propertylist_update_float(pro_list,
724 "ESO QC CENTROID MEASURED FWHM AT Y", (
float)centroid_fwhm_y);
726 if (cpl_msg_get_level() <= CPL_MSG_DEBUG) {
727 cpl_msg_info(cpl_func,
"centroid_x: %f centroid_y: %f", centroid_x,
729 cpl_msg_info(cpl_func,
"centroid_fwhm_x: %f centroid_fwhm_y: %f",
730 centroid_fwhm_x, centroid_fwhm_y);
734 cpl_array_delete(parameters);
735 cpl_array_delete(err_params);
736 cpl_array_delete(fit_params);
738 return cpl_error_get_code();
770 static cpl_error_code midi_image_get_fwhm(
771 const cpl_image * in,
778 const int minimum_size = 5;
783 if (fwhm_y != NULL) *fwhm_y = -1;
784 cpl_ensure_code(fwhm_x, CPL_ERROR_NULL_INPUT);
786 cpl_ensure_code(fwhm_y, CPL_ERROR_NULL_INPUT);
789 half_max = 0.5 * cpl_image_get(in, xpos, ypos, &is_rejected);
791 cpl_ensure_code(is_rejected >= 0, cpl_error_get_code());
792 cpl_ensure_code(!is_rejected, CPL_ERROR_DATA_NOT_FOUND);
794 cpl_ensure_code(half_max > 0, CPL_ERROR_DATA_NOT_FOUND);
797 if (cpl_image_get_size_x(in) >= minimum_size) {
798 cpl_errorstate pstate;
801 cpl_vector * row = cpl_vector_new_from_image_row(in, ypos);
804 cpl_ensure_code(row, cpl_error_get_code());
806 pstate = cpl_errorstate_get();
810 if (cpl_errorstate_is_equal(pstate))
811 *fwhm_x = midi_vector_get_fwhm(row, xpos, half_max);
813 cpl_vector_delete(row);
816 cpl_ensure_code(cpl_errorstate_is_equal(pstate), cpl_error_get_code());
821 if (cpl_image_get_size_y(in)>= minimum_size) {
822 cpl_errorstate pstate;
825 cpl_vector * col = cpl_vector_new_from_image_column(in, xpos);
828 cpl_ensure_code(col, cpl_error_get_code());
830 pstate = cpl_errorstate_get();
835 if (cpl_errorstate_is_equal(pstate))
836 *fwhm_y = midi_vector_get_fwhm(col, ypos, half_max);
838 cpl_vector_delete(col);
841 cpl_ensure_code(cpl_errorstate_is_equal(pstate), cpl_error_get_code());
844 return CPL_ERROR_NONE;
860 static double midi_vector_get_fwhm(
861 const cpl_vector * vec,
865 const double * vec_data;
867 double x_left, x_right;
872 cpl_ensure(vec, CPL_ERROR_NULL_INPUT, -1.0);
873 nelem = cpl_vector_get_size(vec);
874 cpl_ensure(pos >= 1, CPL_ERROR_ILLEGAL_INPUT, -1.0);
875 cpl_ensure(pos <= nelem, CPL_ERROR_ILLEGAL_INPUT, -1.0);
877 vec_data = cpl_vector_get_data_const(vec);
880 if (vec_data[pos - 1] <= half_max)
return -1.0;
886 while ((vec_data[i] > half_max) && (i > 0)) i--;
887 if (vec_data[i] > half_max)
return -1.0;
895 x_left = i + (half_max-y_1) / (y_2-y_1);
903 while ((vec_data[i] > half_max) && (i < nelem-1)) i++;
904 if (vec_data[i] > half_max)
return -1.0;
912 x_right = i + (half_max-y_2) / (y_2-y_1);
916 if (x_right < x_left || x_right - x_left > FLT_MAX)
return -1;
918 return x_right - x_left;
925 static int midi_isnan(
double value)
927 #if defined HAVE_ISNAN && HAVE_ISNAN
930 return value != value;