MIDI Pipeline Reference Manual  2.8.3
imageProcessing.c
1 
2 /******************************************************************************
3 *******************************************************************************
4 * European Southern Observatory
5 * VLTI MIDI Maintenance Templates Software
6 *
7 * Module name: imageProcessing.c
8 * Description: Contains routines for image processing
9 *
10 * History:
11 * 14-Jun-04 (csabet) created
12 *******************************************************************************
13 ******************************************************************************/
14 
15 /******************************************************************************
16 * Compiler directives
17 ******************************************************************************/
18 
19 /******************************************************************************
20 * Include files
21 ******************************************************************************/
22 #include <sys/stat.h>
23 #include <math.h>
24 #include <stdio.h>
25 #include "qfits.h"
26 #include "midiGlobal.h"
27 #include "midiLib.h"
28 #include "imageProcessing.h"
29 #include "statistics.h"
30 #include "errorHandling.h"
31 #include "diagnostics.h"
32 #include "cpl_image_io.h"
33 #include "cpl_image_basic.h"
34 #include "complex_midi.h"
35 #include "fft.h"
36 #include <cpl.h>
37 
38 /**********************************************************
39 * Constant definitions
40 **********************************************************/
41 #define CIRCLE_TO_SQUARE (0.350)
42 
43 /**********************************************************
44 * Global Variables
45 **********************************************************/
46 
47 /*============================ C O D E A R E A ===========================*/
48 
49 
50 
51 /******************************************************************************
52 * European Southern Observatory
53 * VLTI MIDI Data Reduction Software
54 *
55 * Module name: getUndispersedPowerSpectrum
56 * Input/Output: See function arguments to avoid duplication
57 * Description: Creates spectrum for all regions together with the dc levels.
58 *
59 * History:
60 * 17-Sep-03 (JM) Initial code
61 * 15-Feb-06 (csabet) Completely restructured and also adapted for SCI_PHOT
62 ******************************************************************************/
63 void getUndispersedPowerSpectrum (
64  ImageFormat *imageFormat, // In: Pointer to image format
65  CompressedData *compressed) // In: Pointer to the compressed data
66 {
67 
68  // Local Declarations
69  // ------------------
70  const char routine[] = "getUndispersedPowerSpectrum";
71  double *inputPtr;
72  struct Complex *input2ft;
73  int i, s, R;
74  float accum, *allSpectrumPtr, *dcLevelsPtr;
75 
76  // Algorithm
77  // ---------
78  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
79  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
80 
81  // Preset FFT
82  SetFFTsize (imageFormat->fftsize);
83 
84  // Allocate the input array for the FFT:
85  FFTarray = (struct Complex *) malloc (MAXFFTSIZE * (sizeof(struct Complex)));
86  input2ft = (struct Complex *) malloc (imageFormat->fftsize * (sizeof(struct Complex)));
87 
88  // Save pointer etc.
89  allSpectrumPtr = compressed->allSpectrum;
90  dcLevelsPtr = compressed->dcLevels;
91 
92  for (R = 0; R < REGIONS_UNDISPERSED; R++)
93  {
94  if (R == 0)
95  inputPtr = compressed->iFringe;
96  else if (R == 1)
97  inputPtr = compressed->iFringe1;
98  else
99  inputPtr = compressed->iFringe2;
100 
101  // Process each scan in turn:
102  for (s = 0; s < imageFormat->numOfScans; s++)
103  {
104  // Process good scans only
105  if (!(compressed->badScanList[s]))
106  {
107  // Reset
108  memset (input2ft, 0, (sizeof(struct Complex)) * imageFormat->fftsize);
109  accum = 0.F;
110  for (i = 0; i < imageFormat->framesPerScan; i++)
111  {
112  // Accumulate to the DC level here. Process good frames and Ignore Sky if any
113  accum += *inputPtr;
114 
115  // Copy to fft input array
116  input2ft[i].r = *inputPtr;
117  inputPtr++;
118  }
119 
120  // DC level of this scan
121  *dcLevelsPtr = accum / ((float) imageFormat->framesPerScan);
122 
123  // Now subtract the dc level from the values we just inputted to the fft input array:
124  for (i = 0; i < imageFormat->framesPerScan; i++)
125  input2ft[i].r -= *dcLevelsPtr;
126 
127  // Increment the pointer
128  dcLevelsPtr++;
129 
130  // Now do the FFT. The output will be in FFTarray
131  FFT (input2ft, FFTlevel);
132 
133  // Now copy the (sqrd mag) of the fft result to the power spectrum output
134  for (i = 0; i < imageFormat->fftsize/2; i++)
135  {
136  *allSpectrumPtr = Cmag2(FFTarray[i]);
137  allSpectrumPtr++;
138  }
139  }
140  else
141  {
142  // Increment pointers
143  dcLevelsPtr++;
144  for (i = 0; i < imageFormat->framesPerScan; i++)
145  inputPtr++;
146  for (i = 0; i < imageFormat->fftsize/2; i++)
147  allSpectrumPtr++;
148  }
149  }
150  }
151 
152  // Create plot data file. For SCI_PHOT it will not be used yet. Not necessary
153  if (plotFile)
154  {
155  if (strcmp (imageFormat->beamCombiner, "SCI_PHOT") == 0)
156  midiCreatePlotFile2D ("SpectrumCombinedDATA2DATA3", "DATA2-DATA3, DATA2 and DATA3 Spectrum",
157  "FFT bins for each Scan", "Power Spectrum", 0, compressed->allSpectrum, 0,
158  imageFormat->allSpectrumLength, 1, 0);
159  else
160  midiCreatePlotFile2D ("SpectrumCombinedDATA1DATA2", "DATA1-DATA2, DATA1 and DATA2 Spectrum",
161  "FFT bins for each Scan", "Power Spectrum", 0, compressed->allSpectrum, 0,
162  imageFormat->allSpectrumLength, 1, 0);
163  }
164 
165  free (input2ft);
166  free (FFTarray);
167 
168  return;
169 }
170 //******************************************************************************
171 
172 
173 /******************************************************************************
174 * European Southern Observatory
175 * VLTI MIDI Data Reduction Software
176 *
177 * Module name: normalizeSignal
178 * Input/Output: See function arguments to avoid duplication
179 * Description: normalizes the content of an array. For instance eachspectrum,
180 * to remove large numbers. FV has problems handling large numbers.
181 *
182 * History:
183 * 11-Nov-03 (csabet) Created
184 ******************************************************************************/
185 void normalizeSignal (
186  int arraySize, /* In: Length of the array */
187  float *signal) /* IO: Pointer to an array */
188 {
189 
190  /* Local Declarations
191  --------------------*/
192  const char routine[] = "normalizeSignal";
193  int i;
194  float maxSignal;
195 
196  /* Algorithm
197  -----------*/
198  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
199  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
200 
201  /* Find maximum. Ignore first two elements */
202  maxSignal = signal[0];
203  for (i = 0; i < arraySize; i++)
204  if (signal[i] > maxSignal) maxSignal = signal[i];
205 
206  /* Normalize signal */
207  for (i = 0; i < arraySize; i++)
208  signal[i] /= maxSignal;
209 
210  return;
211 }
212 /*****************************************************************************/
213 
214 
215 
216 
217 /******************************************************************************
218 * European Southern Observatory
219 * VLTI MIDI Maintenance Templates Software
220 *
221 * Module name: computeFrameFlux
222 * Input/Output: See function arguments to avoid duplication
223 * Description: Computes the total flux in the given frame
224 *
225 * History:
226 * 26-Aug-04 (csabet) Created
227 ******************************************************************************/
228 void computeFrameFlux (
229  short int *inData, // In: Pointer to the input data
230  int frame, // In: Frame number
231  int scalingOffset, // In: Scaling factor
232  ImageFormat *format, // In: Pointer to the image format
233  MidiCoords *target, // In: Region to cover
234  float *flux, // Ou: Computed flux
235  int *pixelCount, // Ou Pixel count
236  int *error) // Ou: Error status
237 
238 {
239 
240  // Local Declarations
241  // ------------------
242  const char routine[] = "computeFrameFlux";
243  int i, yWin, xWin, fileSpan, frameSpan, subWindowSize;
244 
245  // Algorithm
246  // ---------
247  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
248  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
249 
250  // Reset status
251  *error = 0;
252  *flux = 0.0;
253  *pixelCount = 0;
254 
255  // Compute flux in the given region
256  subWindowSize = format->iXWidth * format->iYWidth;
257  fileSpan = frame * subWindowSize;
258  for (yWin = 0; yWin < format->iYWidth; yWin++)
259  {
260  frameSpan = yWin * format->iXWidth;
261  for (xWin = 0; xWin < format->iXWidth; xWin++)
262  {
263  // Compute total flux
264  i = fileSpan + frameSpan + xWin;
265  if (isnan (inData[i]))
266  {
267  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Corrupted data");
268  *error = 1;
269  return;
270  }
271  if (xWin >= (int) (target->xCoord) && xWin <= (int) (target->dxCoord) &&
272  yWin >= (int) (target->yCoord) && yWin <= (int) (target->dyCoord))
273  {
274  *flux += (float) (inData[i] + scalingOffset);
275  (*pixelCount)++;
276  }
277  }
278  }
279 
280  if (diagnostic)
281  {
282  cpl_msg_info(cpl_func,"\nCoordinates and flux results for frame %d: \n", frame);
283  cpl_msg_info(cpl_func,"====================================== \n");
284  cpl_msg_info(cpl_func," Image coordinates = %f %f %f %f\n", target->xCoord, target->yCoord, target->dxCoord, target->dyCoord);
285  cpl_msg_info(cpl_func," Flux = %f\n", *flux);
286  cpl_msg_info(cpl_func," Pixel count = %d\n", *pixelCount);
287  fprintf (midiReportPtr, "\nCoordinates and flux results for frame %d: \n", frame);
288  fprintf (midiReportPtr, "====================================== \n");
289  fprintf (midiReportPtr, " Image coordinates = %f %f %f %f\n", target->xCoord, target->yCoord, target->dxCoord, target->dyCoord);
290  fprintf (midiReportPtr, " Flux = %f\n", *flux);
291  fprintf (midiReportPtr, " Pixel count = %d\n", *pixelCount);
292  }
293 
294  return;
295 }
296 //******************************************************************************
297 
298 
299 
300 
301 /******************************************************************************
302 * European Southern Observatory
303 * VLTI MIDI Maintenance Templates Software
304 *
305 * Module name: computeImageFlux
306 * Input/Output: See function arguments to avoid duplication
307 * Description: Computes the total flux in the given image
308 *
309 * History:
310 * 26-Aug-04 (csabet) Created
311 ******************************************************************************/
312 void computeImageFlux (
313  float *image, // In: Pointer to the input data
314  ImageFormat *format, // In: Pointer to the image format
315  MidiCoords *target, // In: Region to cover
316  float *flux, // Ou: Computed flux
317  int *pixelCount, // Ou Pixel count
318  int *error) // Ou: Error status
319 
320 {
321 
322  // Local Declarations
323  // ------------------
324  const char routine[] = "computeImageFlux";
325  int i, yWin, xWin, frameSpan;
326 
327  // Algorithm
328  // ---------
329  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
330  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
331 
332  // Reset status
333  *error = 0;
334  *flux = 0.0;
335  *pixelCount = 0;
336 
337  // Compute flux in the given region
338  for (yWin = 0; yWin < format->iYWidth; yWin++)
339  {
340  frameSpan = yWin * format->iXWidth;
341  for (xWin = 0; xWin < format->iXWidth; xWin++)
342  {
343  // Compute total flux
344  i = frameSpan + xWin;
345  if (xWin >= (int) (target->xCoord) && xWin <= (int) (target->dxCoord) &&
346  yWin >= (int) (target->yCoord) && yWin <= (int) (target->dyCoord))
347  {
348  *flux += (float) (image[i]);
349  (*pixelCount)++;
350  }
351  }
352  }
353 
354  return;
355 }
356 //******************************************************************************
357 
358 
359 /******************************************************************************
360 * European Southern Observatory
361 * VLTI MIDI Maintenance Templates Software
362 *
363 * Module name: createAveragedImage
364 * Input/Output: See function arguments to avoid duplication
365 * Description: Creates an averaged image from the FITS file
366 *
367 * History:
368 * 18-Aug-04 (csabet) Created
369 ******************************************************************************/
370 void createAveragedImage (
371  short int *inData, // In: Pointer to the input data
372  float scalingOffset, // In: Scaling Offset
373  ImageFormat *format, // In: Pointer to the image format
374  float *image) // Ou: Output image
375 
376 {
377  // Local Declarations
378  // ------------------
379  const char routine[] = "createAveragedImage";
380  int i, count, pixel, frame, subWindowSize;
381 
382  // Algorithm
383  // ---------
384  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
385  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
386 
387  // Reset status
388  subWindowSize = format->iXWidth * format->iYWidth;
389 
390  for (pixel = 0; pixel < subWindowSize; pixel++)
391  {
392  // Along the time axis (frame)
393  image[pixel] = 0;
394  count = 0;
395  for (frame = 0; frame < format->numOfFrames; frame++)
396  {
397  // Load each pixel data along the time axis
398  i = frame * subWindowSize + pixel;
399  if (isnan (inData[i]))
400  {
401  sprintf (midiMessage, "Found bad pixel on frame %d", frame);
402  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
403  }
404  else
405  {
406  count++;
407  image[pixel] += (float) (inData[i] + scalingOffset);
408  }
409  }
410 
411  // Compute average image
412  image[pixel] /= count;
413  }
414 
415  return;
416 }
417 /*****************************************************************************/
418 
419 
420 
421 /******************************************************************************
422 * European Southern Observatory
423 * VLTI MIDI Maintenance Templates Software
424 *
425 * Module name: createFitsImage
426 * Input/Output: See function arguments to avoid duplication
427 * Description: Creates a fits file with the following format:
428 * outFileDir, outRootName, batchNumber, fileNumber
429 * e.g. MIDI_detRon_b1.ai1.fits
430 * Where "ai1" means "Average Image 1"
431 *
432 * History:
433 * 31-Aug-04 (csabet) Created
434 ******************************************************************************/
435 void createFitsImage (
436  const char *regionOrFile, // In: Indicating region or file
437  const char *name, // In: Name of the image file
438  char *inFitsName, // In: Name of FITS file
439  int xLength, // In: X length
440  int yLength, // In: Y length
441  float *image) // In: Image of the file
442 {
443 
444  // Local Declarations
445  // ------------------
446  const char routine[] = "createFitsImage";
447  qfits_header *pHeaderOut;
448  FILE *imagePtr;
449  qfitsdumper qdImage;
450  char *sWidthX, *sWidthY, *stringOut;
451  struct stat buf;
452 
453  // Algorithm
454  // ---------
455  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
456  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
457 
458  cpl_msg_info(cpl_func,"\nCreating an image from %s for batch %d \n", regionOrFile, batchNumber);
459  cpl_msg_info(cpl_func,"----------------------------------- \n");
460  fprintf (midiReportPtr, "\nCreating an image from %s for batch %d \n", regionOrFile, batchNumber);
461  fprintf (midiReportPtr, "----------------------------------- \n");
462 
463  // Allocate memory
464  stringOut = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
465  sWidthY = (char *) calloc (MIN_STRING_LENGTH, sizeof (char));
466  sWidthX = (char *) calloc (MIN_STRING_LENGTH, sizeof (char));
467 
468  // Write all NAXIS values as character strings
469  sprintf (sWidthY, "%d", yLength);
470  sprintf (sWidthX, "%d", xLength);
471 
472  // Add primary Header
473  if (diagnostic)cpl_msg_info(cpl_func," Extracting primary header from input FITS file %s \n", inFitsName);
474  fprintf(midiReportPtr, " Extracting primary header from input FITS file %s \n", inFitsName);
475  pHeaderOut = qfits_header_read (inFitsName);
476  if (pHeaderOut == NULL)
477  {
478  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot extract primary header from input FITS file");
479  free (sWidthY);
480  free (sWidthX);
481  free (stringOut);
482  return;
483  }
484 
485  // Updates header for the DetRon output file
486  qfits_header_mod (pHeaderOut, "BITPIX","-32", "number of bits per pixel");
487  qfits_header_mod (pHeaderOut, "NAXIS", "2", "number of data axes");
488  qfits_header_add (pHeaderOut, "NAXIS1", sWidthX, "", "");
489  qfits_header_add (pHeaderOut, "NAXIS2", sWidthY, "", "");
490 
491 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN1 NX", sWidthX, "# of pixels along x");
492 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN1 NY", sWidthY, "# of pixels along y");
493 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN1 STRX", "1", "Lower left pixel in x");
494 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN1 STRY", "1", "Lower left pixel in y");
495 
496 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN2 NX", sWidthX, "# of pixels along x");
497 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN2 NY", sWidthY, "# of pixels along y");
498 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN2 STRX", "1", "Lower left pixel in x");
499 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET WIN2 STRY", "1", "Lower left pixel in y");
500 
501 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET CHIP NX", sWidthX, "# of pixels along x");
502 // qfits_header_mod (pHeaderOut, "HIERARCH ESO DET CHIP NY", sWidthY, "# of pixels along y");
503 
504  qfits_header_mod (pHeaderOut, "INSTRUME", "MIDI", "MIDI Raw Data Display FITS created by DRS pipeline" );
505 
506  // Create file and dump FITS Header for DetRon output file
507  sprintf (stringOut, "%s%s.%s.fits", outFileDir, outRootName, name);
508  if (stat (stringOut, &buf) == 0) remove (stringOut); // If the file exist delete it
509  if ((imagePtr = fopen (stringOut, "w")) == NULL)
510  {
511  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot create Image of the data file");
512  free (sWidthY);
513  free (sWidthX);
514  free (stringOut);
515  qfits_header_destroy (pHeaderOut);
516  return;
517  }
518 
519  cpl_msg_info(cpl_func," Created an Image file: %s \n", stringOut);
520  fprintf (midiReportPtr, " Created an Image file: %s \n", stringOut);
521 
522  qfits_header_dump (pHeaderOut, imagePtr);
523  fclose (imagePtr);
524 
525  // Done writing header, close structure
526  qfits_header_destroy (pHeaderOut);
527 
528  // Dumps Fringe into the Detector Readout Noise file
529  qdImage.filename = stringOut;
530  qdImage.npix = xLength * yLength;
531  qdImage.ptype = PTYPE_FLOAT;
532  qdImage.fbuf = image;
533  qdImage.out_ptype = BPP_IEEE_FLOAT;
534 
535  qfits_pixdump (&qdImage);
536 
537  /* Zero-pad the FITS file */
538  qfits_zeropad((char *)stringOut);
539 
540  // Release memory
541  free (sWidthY);
542  free (sWidthX);
543  free (stringOut);
544 
545  return;
546 }
547 /*****************************************************************************/
548 
549 
550 
551 /******************************************************************************
552 * European Southern Observatory
553 * VLTI MIDI Maintenance Templates Software
554 *
555 * Module name: midiGaussianFit
556 * Input/Output: See function arguments to avoid duplication
557 * Description: This is a wrapper for the CPL library function
558 *
559 * History:
560 * 18-Aug-04 (csabet) Created
561 ******************************************************************************/
562 void midiGaussianFit (
563  int fileNumber, // In: File number
564  int dimension, // In: Dimensionality
565  float *image, // In: Pointer to an image
566  int xImage, // In: X size of image
567  int yImage, // In: Y size of image
568  int xP, // In: X coordinate of the central pinhole
569  int yP, // In: Y coordinate of the central pinhole
570  int sizeP, // In: Search size for the target
571  double *xT, // Ou: X coordinate of the target centroid
572  double *yT, // Ou: Y coordinate of the target centroid
573  double *sizeXT, // Ou: Width of the target
574  double *sizeYT, // Ou: Y-Width of the target
575  int *error) // Ou: Error status
576 
577 {
578 
579  // Local Declarations
580  // ------------------
581  const char routine[] = "midiGaussianFit";
582  cpl_image *cplImage;
583  double sigX, sigY, norm;
584 
585  // Algorithm
586  // ---------
587  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
588  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
589 
590  // Reset status
591  *error = 0;
592  *xT = 0.0;
593  *yT = 0.0;
594  *sizeXT = 0.0;
595  *sizeYT = 0.0;
596 
597  if (dimension == 1)
598  {
599  midiGetFWHM (fileNumber, image, xImage, yImage, sizeP, xT, yT, sizeXT, sizeYT, error);
600  if (*error) midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot find centroid");
601  }
602  else if (dimension == 2)
603  {
604  // Using a 2D Gaussian fit find the coordinates of the targets. First build a cpl_image
605  cplImage = cpl_image_wrap_float (xImage, yImage, image);
606 
607  // There is a memory leak inside "cpl_image_gaussian_fit"
608  if (cpl_image_fit_gaussian (cplImage, xP, yP, sizeP, &norm, xT, yT, &sigX, &sigY, NULL, NULL)!=CPL_ERROR_NONE){
609  *error = 1;
610  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot find the centroid");
611  cpl_image_unwrap (cplImage);
612  return;
613  }
614 
615  *sizeXT = 0.5 * (sigX + sigY);
616  *sizeYT = 0.5 * (sigX + sigY);
617 
618  cpl_image_unwrap (cplImage);
619  }
620  else
621  {
622  *error = 1;
623  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Invalid dimensionality");
624  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot find centroid");
625  return;
626  }
627 
628  // If all is well print the result
629  if (!(*error))
630  {
631  cpl_msg_info(cpl_func," Target centroid = (x, y, X-Width, Y-Width) %f %f %f %f\n",
632  *xT, *yT, *sizeXT, *sizeYT);
633  fprintf (midiReportPtr, " Target centroid = (x, y, X-Width, Y-Width) %f %f %f %f\n",
634  *xT, *yT, *sizeXT, *sizeYT);
635  }
636 
637  return;
638 }
639 //*****************************************************************************
640 
641 
642 /******************************************************************************
643 * European Southern Observatory
644 * VLTI MIDI Maintenance Templates Software
645 *
646 * Module name: midiGaussian_1d_fit
647 * Input/Output: See function arguments to avoid duplication
648 * Description: This function performs a 1d Gaussian fit
649 *
650 * History:
651 * 23-Sep-04 (csabet) Created
652 ******************************************************************************/
653 void midiGaussian_1d_fit (
654  float *array, // In: Pointer to an array of data
655  int length, // In: length of the array
656  int sizeS, // In: Search size for the target
657  float *centre, // Ou: Position of the target centroid
658  float *sizeT, // Ou: Size of the target
659  float *fluxErr2Min, // Ou: Flux in the search region
660  int *error) // Ou: Error status
661 
662 {
663 
664  // Local Declarations
665  // ------------------
666  const char routine[] = "midiGaussian_1d_fit";
667  int i, j, l, searchLimit, halfGauss;
668  float *gaussian, sigma, exponentConst, fluxErr2;
669  char *fileString, *title;
670 
671  // Algorithm
672  // ---------
673  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
674  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
675 
676  // Reset status
677  *error = 0;
678  *fluxErr2Min = 0.0;
679  *centre = 0.0;
680  *sizeT = 0.0;
681  sigma = 0.0;
682 
683  // Exception handling. Make sure sizeS is odd
684  if (diagnostic > 2) cpl_msg_info(cpl_func,"search span before = %d\n", sizeS);
685  if (!(sizeS & 1)) sizeS += 1;
686  if (diagnostic > 2) cpl_msg_info(cpl_func,"search span after = %d\n", sizeS);
687  searchLimit = length - sizeS;
688  if (searchLimit <= sizeS)
689  {
690  *error = 1;
691  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Search window too large");
692  return;
693  }
694 
695  // Allocate memory
696  gaussian = (float *) calloc (sizeS, sizeof (float));
697 
698  // Determine the symetrical search span
699  halfGauss = (sizeS >> 1);
700 
701  // Plot the input array
702  if (diagnostic > 2)
703  midiCreatePlotFile2D ("InputArray", "Input Array", "X", "Y", 0, array, 0, length, 1, 0);
704 
705  // Search with different values of Gaussian sigma
706  for (l = 0; l < GAUSSIAN_SIGMA_SPAN; l++)
707  {
708  // Define the Normalized Gaussian with a=0
709  sigma += 0.25;
710  exponentConst = (-0.5) / (sigma * sigma);
711  for (i = -halfGauss; i <= halfGauss; i++)
712  {
713  j = halfGauss+i;
714  gaussian[j] = exp (exponentConst * i * i);
715  if (plotFile && diagnostic > 2)
716  {
717  fileString = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
718  title = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
719  sprintf (fileString , "GaussianWithSigma%f", sigma);
720  sprintf (title , "Gaussian with %f Sigma", sigma);
721  midiCreatePlotFile2D (fileString, title, "Span", "Sigma", 0, gaussian, 0, sizeS, 1, 0);
722  free (fileString);
723  free (title);
724  if (diagnostic > 2)
725  {
726  cpl_msg_info(cpl_func," Gaussian %d = %8.8f\n", i, gaussian[j]);
727  fprintf (midiReportPtr, " Gaussian %d = %8.8f\n", i, gaussian[j]);
728  }
729  }
730  }
731 
732  // Find the section where squared error is minimum
733  // -----------------------------------------------
734  for (i = 0; i < searchLimit; i++)
735  {
736  // Correlate flux
737  fluxErr2 = 0.0;
738  for (j = 0; j < sizeS; j++)
739  fluxErr2 += ( (gaussian[j] - array[i+j]) * (gaussian[j] - array[i+j]) );
740 
741  // Initialise the mimimum
742  if (l == 0 && i == 0) *fluxErr2Min = fluxErr2;
743  else
744  {
745  if (fluxErr2 < *fluxErr2Min)
746  {
747  *fluxErr2Min = fluxErr2;
748  *centre = (float) (i + 0.5 * sizeS);
749  *sizeT = (float) (3.0 * sigma);
750  }
751  }
752  }
753  }
754 
755  // Release memory
756  free (gaussian);
757 
758  return;
759 }
760 //*****************************************************************************
761 
762 
763 /******************************************************************************
764 * European Southern Observatory
765 * VLTI MIDI Maintenance Templates Software
766 *
767 * Module name: midiGaussianSmooth
768 * Input/Output: See function arguments to avoid duplication
769 * Description: Using a Gaussian fit computes the refined position of peak
770 * of a pinhole spectra
771 *
772 * History:
773 * 31-Aug-05 (csabet) Created
774 ******************************************************************************/
775 float midiGaussianSmooth ( // Ou: Refined peak
776  float *array, // In: Pointer to an array of normalised data
777  int length, // In: length of the array
778  int peakIn, // In: Approximate peak
779  int searchSpan, // In: Search span
780  int *error) // Ou: Error status
781 
782 {
783 
784  // Local Declarations
785  // ------------------
786  const char routine[] = "midiGaussianSmooth";
787  int i, j, l, start, end, halfGauss;
788  float *gaussian, sigma, exponentConst, fluxErr2, xCPH, fluxErr2Min;
789  char *fileString, *title;
790 
791  // Algorithm
792  // ---------
793  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
794  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
795 
796  // Reset status
797  *error = 0;
798  fluxErr2Min = 0.0;
799  sigma = 0.0;
800  xCPH = 0.0;
801 
802  // Exception handling. Make sure searchSpan is odd
803  if (diagnostic > 2) cpl_msg_info(cpl_func,"search span before = %d\n", searchSpan);
804  if (!(searchSpan & 1)) searchSpan += 1;
805  if (diagnostic > 2) cpl_msg_info(cpl_func,"search span after = %d\n", searchSpan);
806  halfGauss = (searchSpan >> 1);
807  start = peakIn - searchSpan;
808  end = peakIn + searchSpan;
809  if ((end > length) || (start < 0))
810  {
811  *error = 1;
812  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Search window too large");
813  return (-1);
814  }
815 
816  // Allocate memory
817  gaussian = (float *) calloc (searchSpan, sizeof (float));
818 
819  // Search with different values of Gaussian sigma
820  for (l = 0; l < GAUSSIAN_SIGMA_SPAN; l++)
821  {
822  // Define the Normalized Gaussian with a=0
823  sigma += 0.25;
824  exponentConst = (-0.5) / (sigma * sigma);
825  for (i = -halfGauss; i <= halfGauss; i++)
826  {
827  j = halfGauss+i;
828  gaussian[j] = exp (exponentConst * i * i);
829  if (plotFile && diagnostic > 2)
830  {
831  fileString = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
832  title = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
833  sprintf (fileString , "GaussianWithSigma%f", sigma);
834  sprintf (title , "Gaussian with %f Sigma", sigma);
835  midiCreatePlotFile2D (fileString, title, "Span", "Sigma", 0, gaussian, 0, searchSpan, 1, 0);
836  cpl_msg_info(cpl_func," Gaussian %d = %8.8f\n", i, gaussian[j]);
837  fprintf (midiReportPtr, " Gaussian %d = %8.8f\n", i, gaussian[j]);
838  }
839  }
840 
841  // Find the section where squared error is minimum
842  // -----------------------------------------------
843  for (i = start; i < end; i++)
844  {
845  // Correlate flux
846  fluxErr2 = 0.0;
847  for (j = 0; j < searchSpan; j++)
848  fluxErr2 += ( (gaussian[j] - array[i+j]) * (gaussian[j] - array[i+j]) );
849 
850  // Initialise the mimimum
851  if ((l == 0) && (i == start))
852  fluxErr2Min = fluxErr2;
853  else
854  {
855  if (fluxErr2 < fluxErr2Min)
856  {
857  fluxErr2Min = fluxErr2;
858  xCPH = (float) (i + 0.5 * searchSpan);
859  }
860  }
861  }
862  }
863 
864  // Release memory
865  free (gaussian);
866 
867  return (xCPH);
868 }
869 //*****************************************************************************
870 
871 
872 /******************************************************************************
873 * European Southern Observatory
874 * VLTI MIDI Data Reduction Software
875 *
876 * Module name: getBadScansFromSpectrumUndisp
877 * Input/Output: See function arguments to avoid duplication
878 * Description: Rejecting bad scans based on the signal/noise values
879 *
880 * History:
881 * 14-Mar-06 (csabet) Created
882 ******************************************************************************/
883 void getBadScansFromSpectrumUndisp (
884  FilterData *filterInfo, // In: Pointer to filter information
885  ImageFormat *format, // In: Points to the image format
886  CompressedData *compressed, // IO: Pointer to compressed data
887  int *error) // Ou: Error status
888 {
889  // Local Declarations
890  //--------------------
891  const char routine[] = "getBadScansFromSpectrumUndisp";
892  int i;
893  float *tempArray;
894 
895  // Algorithm
896  // ---------
897  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
898  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
899 
900  cpl_msg_info(cpl_func,"\nRejecting scans based on Signal/Noise \n");
901  cpl_msg_info(cpl_func,"------------------------------------- \n");
902  fprintf (midiReportPtr, "\nRejecting scans based on Signal/Noise \n");
903  fprintf (midiReportPtr, "------------------------------------- \n");
904 
905  // Reset
906  *error = 0;
907 
908  // Get bad scans due to weak signal/noise
909  rejectScansOnWeakSNRUndisp (filterInfo, format, compressed, error);
910 
911  // Now compute number of bad scans
912  format->numOfScansRejected = 0;
913  format->numOfScansProcessed = 0;
914  for (i = 0; i < format->numOfScans; i++)
915  {
916  if (compressed->badScanList[i])
917  format->numOfScansRejected++;
918  }
919  format->numOfScansProcessed = format->numOfScans - format->numOfScansRejected;
920 
921  // Create plot file
922  if (plotFile && diagnostic)
923  {
924  tempArray = (float *) calloc (format->numOfScans, sizeof (float));
925  for (i = 0; i < format->numOfScans; i++)
926  {
927  if (compressed->badScanList[i] == 0)
928  tempArray[i] = 0.0;
929  else
930  tempArray[i] = compressed->badScanList[i];
931  }
932  midiCreatePlotFile2D ("BadScanList", "Bad Scan List", "Scan", "Failure ID",
933  0, tempArray, 0, format->numOfScans, 1, 0);
934  free (tempArray);
935  }
936 
937  // Report the bad scan list
938  if (diagnostic) cpl_msg_info(cpl_func,"\nBad Scan List \n");
939  if (diagnostic) cpl_msg_info(cpl_func,"------------- \n");
940  fprintf (midiReportPtr, "\nBad Scan List QCLOG \n");
941  fprintf (midiReportPtr, "------------- QCLOG \n");
942  for (i = 0; i < format->numOfScans; i++)
943  {
944  if (diagnostic) cpl_msg_info(cpl_func,"%3d %3d \n", i, compressed->badScanList[i]);
945  fprintf (midiReportPtr, "%3d %3d QCLOG \n", i, compressed->badScanList[i]);
946  }
947  // Report the bad scan list
948  cpl_msg_info(cpl_func,"Number of scans to process = %3d \n", format->numOfScansProcessed);
949  cpl_msg_info(cpl_func,"Number of scans rejected = %3d \n", format->numOfScansRejected);
950  fprintf (midiReportPtr, "Number of scans to process = %3d QCLOG \n", format->numOfScansProcessed);
951  fprintf (midiReportPtr, "Number of scans rejected = %3d QCLOG \n", format->numOfScansRejected);
952  if (diagnostic)
953  {
954  cpl_msg_info(cpl_func,"Failure ID \n");
955  cpl_msg_info(cpl_func,"---------- \n");
956  cpl_msg_info(cpl_func,"1 = Bit 1, indicates a TIME error \n");
957  cpl_msg_info(cpl_func,"2 = Bit 2, indicates an LOCALOPD error \n");
958  cpl_msg_info(cpl_func,"4 = Bit 3, indicates an OPD error \n");
959  cpl_msg_info(cpl_func,"8 = Bit 4, indicates a Bad DATA \n");
960  cpl_msg_info(cpl_func,"16 = Bit 5, indicates a chopping problem (TARTYPE2) \n");
961  cpl_msg_info(cpl_func,"32 = Bit 6, indicates a Delay Line Jump \n");
962  cpl_msg_info(cpl_func,"64 = Bit 7, indicates an Unwanted Region \n");
963  cpl_msg_info(cpl_func,"128 = Bit 8, indicates a Weak Signal/Noise \n");
964  cpl_msg_info(cpl_func,"256 = Bit 9, indicates a SKY Background \n");
965  cpl_msg_info(cpl_func,"512 = Bit 10, indicates a TARTYPE Cross error. e.g. region 0 different to region 1 \n");
966  cpl_msg_info(cpl_func,"\nHence a number such as 168 indicates bits 4, 6 and 8 were set \n\n");
967  }
968 
969  fprintf (midiReportPtr, "Failure ID QCLOG \n");
970  fprintf (midiReportPtr, "---------- QCLOG \n");
971  fprintf (midiReportPtr, "1 = Bit 1, indicates a TIME error \n");
972  fprintf (midiReportPtr, "2 = Bit 2, indicates an LOCALOPD error \n");
973  fprintf (midiReportPtr, "4 = Bit 3, indicates an OPD error \n");
974  fprintf (midiReportPtr, "8 = Bit 4, indicates a Bad DATA \n");
975  fprintf (midiReportPtr, "16 = Bit 5, indicates a chopping problem (TARTYPE2) \n");
976  fprintf (midiReportPtr, "32 = Bit 6, indicates a Delay Line Jump \n");
977  fprintf (midiReportPtr, "64 = Bit 7, indicates an Unwanted Region \n");
978  fprintf (midiReportPtr, "128 = Bit 8, indicates a Weak Signal/Noise \n");
979  fprintf (midiReportPtr, "256 = Bit 9, indicates a SKY Background \n");
980  fprintf (midiReportPtr, "512 = Bit 10, indicates a TARTYPE Cross error. e.g. region 0 different to region 1 \n");
981  fprintf (midiReportPtr, "\nHence a number such as 168 indicates bits 4, 6 and 8 were set QCLOG \n\n");
982 
983  if (format->numOfScansProcessed < 1)
984  {
985  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "No Scan to process");
986  *error = 1;
987  }
988 
989  return;
990 }
991 /*****************************************************************************/
992 
993 
994 
995 
996 /******************************************************************************
997 * European Southern Observatory
998 * VLTI MIDI Data Reduction Software
999 *
1000 * Module name: rejectScansOnWeakSNRUndisp
1001 * Input/Output: See function arguments to avoid duplication
1002 * Description: Uses Power Spectrum to get the bad scans. This routine
1003 * is used for HIGH_SENS UNDISPERSED processing
1004 *
1005 * History:
1006 * 15-Mar-06 (csabet) Created
1007 ******************************************************************************/
1008 void rejectScansOnWeakSNRUndisp (
1009  FilterData *filterInfo, // In: Pointer to filter information
1010  ImageFormat *format, // In: Points to the image format
1011  CompressedData *compressed, // IO: Pointer to compressed data
1012  int *error) // Ou: Error status
1013 {
1014  // Local Declarations
1015  //--------------------
1016  const char routine[] = "rejectScansOnWeakSNRUndisp";
1017  float *sigPtr, *spectrum, median, peak, ratio, calib;
1018  int i, j, fftSizeHalf, peakIndex, loF, hiF;
1019  char *fileName, *title;
1020 
1021  // Algorithm
1022  // ---------
1023  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
1024  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
1025 
1026  // Initialization
1027  *error = 0;
1028  fftSizeHalf = (format->fftsize >> 1);
1029 
1030  // Compute indices of the valid frequency range
1031  calib = format->optFreqCal / ((float) format->fftsize);
1032  loF = (int) (filterInfo->optFreqLo / calib);
1033  hiF = (int) (filterInfo->optFreqHi / calib);
1034  if (hiF > format->fftsize/2) hiF = format->fftsize/2;
1035 
1036  // Allocate memory
1037  spectrum = (float *) calloc (fftSizeHalf, sizeof (float));
1038 
1039  // Analyse spectrum for each scan
1040  for (i = 0; i < format->numOfScans; i++)
1041  {
1042  sigPtr = compressed->allSpectrum + i * fftSizeHalf;
1043 
1044  // Process good scans only
1045  if (!(compressed->badScanList[i]))
1046  {
1047  // Load spectrum for this scan
1048  for (j = 0; j < fftSizeHalf; j++)
1049  spectrum[j] = *sigPtr++;
1050 
1051  // Analyse the scan spectrum
1052  peak = signalPeak (spectrum, 0, fftSizeHalf, &peakIndex);
1053  median = signalMedian (spectrum, 0, fftSizeHalf);
1054  ratio = peak/median;
1055 
1056  // Check validity of the peak power
1057  if ((ratio < 10.0) || (peakIndex < loF) || (peakIndex > hiF))
1058  compressed->badScanList[i] |= BSL_SNR_ERROR;
1059 
1060  // Plot
1061  if (plotFile && diagnostic > 2)
1062  {
1063  if (compressed->badScanList[i]) cpl_msg_info(cpl_func,"\n <<ERROR>>: Scan %3d rejected \n\n", i);
1064  cpl_msg_info(cpl_func," Expected low frequency index = %3d \n", loF);
1065  cpl_msg_info(cpl_func," Expected high frequency index = %3d \n", hiF);
1066  cpl_msg_info(cpl_func," Found peak index at = %3d \n", peakIndex);
1067  cpl_msg_info(cpl_func," peak/median = %f \n", ratio);
1068  if (compressed->badScanList[i]) fprintf (midiReportPtr, "\n <<ERROR>>: Scan %3d rejected \n\n", i);
1069  fprintf (midiReportPtr, " Expected low frequency index = %3d \n", loF);
1070  fprintf (midiReportPtr, " Expected high frequency index = %3d \n", hiF);
1071  fprintf (midiReportPtr, " Found peak index at = %3d \n", peakIndex);
1072  fprintf (midiReportPtr, " peak/median = %f \n", ratio);
1073 
1074  fileName = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1075  title = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1076  sprintf (fileName, "SpectrumScan%d", i);
1077  sprintf (title, "Power Spectrum. Scan %d", i);
1078  midiCreatePlotFile2D (fileName, title, "Frequancy bin", "Power Spectrum",
1079  1, spectrum, 0, fftSizeHalf, 1, 0);
1080  free (fileName);
1081  free (title);
1082  }
1083  }
1084  }
1085 
1086  // release memory
1087  free (spectrum);
1088 
1089  return;
1090 }
1091 /*****************************************************************************/
1092 
1093 
1094 
1095 
1096 /******************************************************************************
1097 * European Southern Observatory
1098 * VLTI MIDI Maintenance Templates Software
1099 *
1100 * Module name: midiGetFWHM
1101 * Input/Output: See function arguments to avoid duplication
1102 * Description: This function computes the centre and size of spectroscopic
1103 * image. The computation will return the Full Width at
1104 * Half Maximum (FWHM) of the image.
1105 *
1106 * History:
1107 * 23-Sep-04 (csabet) Created
1108 ******************************************************************************/
1109 void midiGetFWHM (
1110  int imageCount, // In: Image number or ID
1111  float *image, // In: Pointer to an image
1112  int xImage, // In: X size of image
1113  int yImage, // In: Y size of image
1114  int sizeP, // In: Search size for the target
1115  double *xT, // Ou: X coordinate of the target centroid
1116  double *yT, // Ou: Y coordinate of the target centroid
1117  double *sizeXT, // Ou: X-Width of the target
1118  double *sizeYT, // Ou: Y-Width of the target
1119  int *error) // Ou: Error status
1120 
1121 {
1122 
1123  // Local Declarations
1124  // ------------------
1125  const char routine[] = "midiGetFWHM";
1126  int i, j, k, l, length, maxLength, start, end;
1127  float *arrayData, centre, *centrePositions, *centreFluxErr2Min,
1128  fluxErr2Min, *span, siztT, fluxMax, *buffImage, max;
1129  char *fileName, *title;
1130 
1131  // Algorithm
1132  // ---------
1133  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
1134  if (diagnostic > 4) fprintf (midiReportPtr, "Invoking routine '%s' \n", routine);
1135 
1136  // Reset status
1137  *error = 0;
1138 
1139  // Allocate memory
1140  length = xImage * yImage;
1141  maxLength = (xImage > yImage) ? xImage : yImage; // get the largest size
1142  arrayData = (float *) calloc (maxLength, sizeof (float));
1143  centrePositions = (float *) calloc (maxLength, sizeof (float));
1144  centreFluxErr2Min = (float *) calloc (maxLength, sizeof (float));
1145  span = (float *) calloc (maxLength, sizeof (float));
1146  buffImage = (float *) calloc (length, sizeof (float));
1147 
1148  // Copy image
1149  for (i = 0; i < length; i++)
1150  buffImage[i] = image[i];
1151 
1152  // Normalize image for a better 2D correlation
1153  fluxMax = buffImage[0];
1154  for (i = 0; i < length; i++)
1155  if (buffImage[i] > fluxMax) fluxMax = buffImage[i];
1156  for (i = 0; i < length; i++)
1157  buffImage[i] /= fluxMax;
1158 
1159  // Determine Y and X-Width
1160  // -----------------------
1161  // For every row, y = 0, .. yImage
1162  for (i = 0; i < yImage; i++)
1163  {
1164  // Load row data, x = 0, .. xImage
1165  for (j = 0; j < xImage; j++)
1166  {
1167  k = j + i * xImage;
1168  arrayData[j] = buffImage[k];
1169  }
1170 
1171  // For every row compute centre, size and Error Mean Squared of the Gaussian profile
1172  midiGaussian_1d_fit (arrayData, xImage, sizeP, &centre, &siztT, &fluxErr2Min, error);
1173  if (*error)
1174  {
1175  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot determine target parameters");
1176  free (arrayData);
1177  free (centrePositions);
1178  free (centreFluxErr2Min);
1179  free (span);
1180  free (buffImage);
1181  return;
1182  }
1183  centrePositions[i] = centre; // Centre positions of the target along Y
1184  centreFluxErr2Min[i] = fluxErr2Min; // Graphical presentation of the target centre
1185  span[i] = siztT; // Variations of Gaussian Span along Y
1186  }
1187 
1188  // Find optimum Y
1189  *sizeXT = 0;
1190  for (i = 0; i < yImage; i++)
1191  {
1192  if (span[i] > *sizeXT)
1193  {
1194  *yT = i;
1195  *sizeXT = span[i];
1196  }
1197  }
1198 
1199  // Find FWHM
1200  max = 0.0;
1201  l = *yT * xImage;
1202  for (j = 0; j < xImage; j++)
1203  {
1204  // Load row data, x = 0, .. xImage
1205  k = j + l;
1206  arrayData[j] = buffImage[k];
1207  if (arrayData[j] > max) max = arrayData[j];
1208  }
1209  start = 0;
1210  end = 0;
1211  for (j = 0; j < xImage; j++)
1212  {
1213  if (arrayData[j] > max/2.0)
1214  {
1215  start = j;
1216  break;
1217  }
1218  }
1219  for (j = xImage-1; j >= 0; j--)
1220  {
1221  if (arrayData[j] > max/2.0)
1222  {
1223  end = j;
1224  break;
1225  }
1226  }
1227  *sizeXT = (end - start) * CIRCLE_TO_SQUARE; // Hopefully taking the central region of the target only
1228 
1229  // Create plot file
1230  if (plotFile)
1231  {
1232  fileName = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1233  title = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1234 
1235  sprintf (fileName, "TargetFluxMinVarX%d", imageCount);
1236  sprintf (title, "Target Flux Minimum Variance for each Y, beam %d", imageCount);
1237  midiCreatePlotFile2D (fileName, title, "Y", "Flux", 0, centreFluxErr2Min, 0, yImage, 1, 0);
1238 
1239  sprintf (fileName, "TargetPositionX%d", imageCount);
1240  sprintf (title, "Target Centre along Y, beam %d", imageCount);
1241  midiCreatePlotFile2D (fileName, title, "Y", "X", 0, centrePositions, 0, yImage, 1, 0);
1242 
1243  sprintf (fileName, "TargetX_WidthAlongY%d", imageCount);
1244  sprintf (title, "Target X-Width along Y, beam %d", imageCount);
1245  midiCreatePlotFile2D (fileName, title, "Y", "X-Width", 0, span, 0, yImage, 1, 0);
1246 
1247  sprintf (fileName, "TargetMaximumProfileAlongY%d", imageCount);
1248  sprintf (title, "Target Maximum Profile at Y = %f, beam %d", *yT, imageCount);
1249  midiCreatePlotFile2D (fileName, title, "X", "Flux", 0, arrayData, 0, xImage, 1, 0);
1250 
1251  // Release memory
1252  free (fileName);
1253  free (title);
1254  }
1255 
1256  // Determine X and Y-Width
1257  // ---------------------
1258  // For every column, x = 0, .. xImage
1259  for (i = 0; i < xImage; i++)
1260  {
1261  // Load column data y = 0, .. yImage
1262  for (j = 0; j < yImage; j++)
1263  {
1264  k = i + j * xImage;
1265  arrayData[j] = buffImage[k];
1266  }
1267 
1268  // For every column compute centre, size and Error Mean Squared of the Gaussian profile
1269  midiGaussian_1d_fit (arrayData, yImage, sizeP, &centre, &siztT, &fluxErr2Min, error);
1270  if (*error)
1271  {
1272  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, "Cannot determine target parameters");
1273  free (arrayData);
1274  free (centrePositions);
1275  free (centreFluxErr2Min);
1276  free (buffImage);
1277  free (span);
1278  return;
1279  }
1280  centrePositions[i] = centre; // Centre positions of the target along X
1281  centreFluxErr2Min[i] = fluxErr2Min; // Graphical presentation of the target centre
1282  span[i] = siztT; // Variations of target Y-Width along X
1283  }
1284 
1285  *sizeYT = 0;
1286  for (i = 0; i < xImage; i++)
1287  {
1288  if (span[i] > *sizeYT)
1289  {
1290  *xT = i;
1291  *sizeYT = span[i];
1292  }
1293  }
1294 
1295  // Find FWHM
1296  max = 0.0;
1297  for (i = 0; i < yImage; i++)
1298  {
1299  // Load column data, y = 0, .. yImage
1300  k = *xT + i * xImage;
1301  arrayData[i] = buffImage[k];
1302  if (arrayData[i] > max) max = arrayData[i];
1303  }
1304  start = 0;
1305  end = 0;
1306  for (j = 0; j < yImage; j++)
1307  {
1308  if (arrayData[j] > max/2.0)
1309  {
1310  start = j;
1311  break;
1312  }
1313  }
1314  for (j = yImage-1; j >= 0; j--)
1315  {
1316  if (arrayData[j] > max/2.0)
1317  {
1318  end = j;
1319  break;
1320  }
1321  }
1322  *sizeYT = (end - start) * CIRCLE_TO_SQUARE; // Hopefully taking the central region of the target only
1323 
1324  // Create plot file
1325  if (plotFile)
1326  {
1327  fileName = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1328  title = (char *) calloc (MAX_STRING_LENGTH, sizeof (char));
1329 
1330  sprintf (fileName, "TargetFluxMinVarY%d", imageCount);
1331  sprintf (title, "Target Flux Minimum Variance for each X, beam %d", imageCount);
1332  midiCreatePlotFile2D (fileName, title, "X", "Flux", 0, centreFluxErr2Min, 0, xImage, 1, 0);
1333 
1334  sprintf (fileName, "TargetPositionY%d", imageCount);
1335  sprintf (title, "Target Centre along Y, beam %d", imageCount);
1336  midiCreatePlotFile2D (fileName, title, "X", "Y", 0, centrePositions, 0, xImage, 1, 0);
1337 
1338  sprintf (fileName, "TargetY_WidthAlongY%d", imageCount);
1339  sprintf (title, "Target Y-Width along Y, beam %d", imageCount);
1340  midiCreatePlotFile2D (fileName, title, "X", "Y-Width", 0, span, 0, xImage, 1, 0);
1341 
1342  sprintf (fileName, "TargetMaximumProfileAlongX%d", imageCount);
1343  sprintf (title, "Target Maximum Profile at X = %f, beam %d", *xT, imageCount);
1344  midiCreatePlotFile2D (fileName, title, "Y", "Flux", 0, arrayData, 0, yImage, 1, 0);
1345 
1346  // Release memory
1347  free (fileName);
1348  free (title);
1349  }
1350 
1351  // Release memory
1352  free (arrayData);
1353  free (centrePositions);
1354  free (centreFluxErr2Min);
1355  free (span);
1356  free (buffImage);
1357 
1358  return;
1359 }
1360 //*****************************************************************************
1361 
1362 
1363 /******************************************************************************
1364 * European Southern Observatory
1365 * VLTI MIDI Data Reduction Software
1366 *
1367 * Module name: removeSkyBackground
1368 * Input/Output: See function arguments to avoid duplication
1369 * Description: Removes sky background.
1370 *
1371 * History:
1372 * 08-Aug-05 (csabet) Created
1373 * 13-Feb-06 (csabet) Completely redesigned
1374 ******************************************************************************/
1375 void removeSkyBackground (
1376  const char *shutterId, // In: AOPEN, BOPEN etc.
1377  enum ProcessingMode processing, // In: Whether DISP or UNDISP
1378  ImageFormat *format, // In: Format parameters
1379  CompressedData *compressed, // Ou: Pointer to the compressed data structure
1380  int *error) // Ou: Error status
1381 
1382 {
1383  // Local Declarations
1384  // ------------------
1385  const char routine[] = "removeSkyBackground";
1386  int i, j, S, T, R, X, shift, start;
1387  char lastType;
1388 
1389  // Algorithm
1390  // ---------
1391  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
1392  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
1393 
1394  sprintf (midiMessage, "Removing sky background from %s", shutterId);
1395  midiReportInfo (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1396 
1397  // Initialise
1398  S = T = 0;
1399  start = 0;
1400  lastType = ' ';
1401  *error = 0;
1402 
1403  // Compute shift
1404  for (i = 0; i < format->numOfFrames; i++)
1405  {
1406  if (compressed->tarType[i] == 'T')
1407  {
1408  if (lastType == 'U' && T && S)
1409  {
1410  T = 0;
1411  S = 0;
1412  }
1413  T++;
1414  if (S)
1415  {
1416  shift = i-start;
1417  for (j = start; j < start+S; j++)
1418  {
1419  if (compressed->tarType[j] != 'U')
1420  {
1421  if (diagnostic > 4)
1422  {
1423  cpl_msg_info(cpl_func,"%4d-%4d %c-%c \n", j+shift, j,
1424  compressed->tarType[j+shift], compressed->tarType[j]);
1425  fprintf (midiReportPtr, "%4d-%4d %c-%c \n", j+shift, j,
1426  compressed->tarType[j+shift], compressed->tarType[j]);
1427  }
1428  compressed->iFringe[j] = compressed->iFringe[j+shift] - compressed->iFringe[j];
1429  compressed->iFringe1[j] = compressed->iFringe1[j+shift] - compressed->iFringe1[j];
1430  compressed->iFringe2[j] = compressed->iFringe2[j+shift] - compressed->iFringe2[j];
1431  if (processing == DISPERSED)
1432  {
1433  for (R = 0; R < format->numOfRegionsToProcess; R++)
1434  {
1435  for (X = 0; X < format->iXWidth; X++)
1436  {
1437  (((compressed->iDispFringe)[R])[X])[j] = (((compressed->iDispFringe)[R])[X])[j+shift] -
1438  (((compressed->iDispFringe)[R])[X])[j];
1439  }
1440  }
1441  }
1442  }
1443  }
1444  i = j+shift-1;
1445  }
1446  }
1447  else if (compressed->tarType[i] == 'S')
1448  {
1449  if (lastType == 'U' && T && S)
1450  {
1451  S = 0;
1452  T = 0;
1453  }
1454  S++;
1455  if (T)
1456  {
1457  shift = i-start;
1458  for (j = start; j < start+T; j++)
1459  {
1460  if (compressed->tarType[j] != 'U')
1461  {
1462  if (diagnostic > 4)
1463  {
1464  cpl_msg_info(cpl_func,"%4d-%4d %c-%c \n", j, j+shift,
1465  compressed->tarType[j], compressed->tarType[j+shift]);
1466  fprintf (midiReportPtr, "%4d-%4d %c-%c \n", j, j+shift,
1467  compressed->tarType[j], compressed->tarType[j+shift]);
1468  }
1469  compressed->iFringe[j] = compressed->iFringe[j] - compressed->iFringe[j+shift];
1470  compressed->iFringe1[j] = compressed->iFringe1[j] - compressed->iFringe1[j+shift];
1471  compressed->iFringe2[j] = compressed->iFringe2[j] - compressed->iFringe2[j+shift];
1472  if (processing == DISPERSED)
1473  {
1474  for (R = 0; R < format->numOfRegionsToProcess; R++)
1475  {
1476  for (X = 0; X < format->iXWidth; X++)
1477  {
1478  (((compressed->iDispFringe)[R])[X])[j] = (((compressed->iDispFringe)[R])[X])[j] -
1479  (((compressed->iDispFringe)[R])[X])[j+shift];
1480  }
1481  }
1482  }
1483  }
1484  }
1485  i = j+shift-1;
1486  }
1487  }
1488  else
1489  {
1490  if (diagnostic > 4)
1491  {
1492  fprintf (midiReportPtr, "%4d %c \n", i, compressed->tarType[i]);
1493  cpl_msg_info(cpl_func,"%4d %c \n", i, compressed->tarType[i]);
1494  }
1495  lastType = 'U';
1496  if ((S && T) || (!S && !T))
1497  {
1498  start = i+1;
1499  }
1500  }
1501  }
1502 
1503  return;
1504 }
1505 /*****************************************************************************/
1506 
1507 
1508 
1509 /******************************************************************************
1510 * European Southern Observatory
1511 * VLTI MIDI Data Reduction Software
1512 *
1513 * Module name: correctTarType
1514 * Input/Output: See function arguments to avoid duplication
1515 * Description: Creates a mask from the tarType. Esures number of consecutive
1516 * T and S are equal. Extras should be labled 'U'. New tarType
1517 * is then created
1518 *
1519 * History:
1520 * 09-Feb-06 (csabet) Created
1521 ******************************************************************************/
1522 long correctTarType (
1523  const char *shutterId,
1524  char *tarType,
1525  float *TimeStamp,
1526  int length,
1527  int *error)
1528 {
1529 
1530  // Local Declarations
1531  // ------------------
1532  const char routine[] = "correctTarType";
1533  int i, j, foundT, foundS, S, T, U, start, end, min, newPair;
1534  char *mask, lastType, lastShot;
1535  long CounterBad=0;
1536 
1537  // Algorithm
1538  // ---------
1539  if (diagnostic > 4) cpl_msg_info(cpl_func,"Invoking routine '%s' \n", routine);
1540  if (diagnostic > 4) fprintf(midiReportPtr, "Invoking routine '%s' \n", routine);
1541 
1542  sprintf (midiMessage, "Checking tarType inconsistencies for %s", shutterId);
1543  midiReportInfo (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1544 
1545  // Initialise
1546  foundT = foundS = 0;
1547  T = S = U = 0;
1548  start = 0;
1549  lastType = ' ';
1550  lastShot = ' ';
1551  newPair = 0;
1552  *error = 0;
1553  i=0;
1554  j=0 ;
1555  CounterBad=0;
1556  // Allocate memory
1557  mask = (char *) calloc (length, sizeof (char));
1558 
1559 /*
1560  Check if the time is valid or not. If not, change tarType to 'U'
1561  If a SUS or TUT sequence is caused by this change, set all previous frames
1562  to 'U' until a TUS or a SUT sequence is re-established
1563 */
1564 
1565  for (i = 0; i < length; i++)
1566  {
1567  if(isnan(TimeStamp[i]))
1568  {
1569  cpl_msg_warning(cpl_func,"Corrupted time stamp in table! ");
1570  cpl_msg_warning(cpl_func,"Changing target type of frame %d "
1571  "from %c to %c", i, tarType[i], 'U');
1572  tarType[i]='U';
1573  CounterBad++;
1574  if(i>0 && i<(length-1) && tarType[i-1]=='S' && tarType[i+1]=='S')
1575  {
1576  j=i-1;
1577  while(tarType[j]!='T' && j>=0)
1578  {
1579  cpl_msg_warning(cpl_func,"Changing target type of frame %d "
1580  "from %c to %c", j, tarType[j], 'U');
1581  tarType[j]='U';
1582  CounterBad++;
1583  j--;
1584  }
1585  }
1586  if(i>0 && i<(length-1) && tarType[i-1]=='T' && tarType[i+1]=='T')
1587  {
1588  j=i-1;
1589  while(tarType[j]!='S' && j>=0)
1590  {
1591  cpl_msg_warning(cpl_func,"Changing target type of frame %d "
1592  "from %c to %c", j, tarType[j], 'U');
1593  tarType[j]='U';
1594  CounterBad++;
1595  j--;
1596  }
1597 
1598  }
1599 
1600  }
1601  }
1602 
1603  for (i = 1; i < length-2; i++)
1604  {
1605  if(tarType[i-1]=='U' && (tarType[i]=='S' || tarType[i]=='T') &&
1606  tarType[i+1]=='U')
1607  {
1608  cpl_msg_warning(cpl_func,"UTU or USU sequence found, "
1609  "correcting to UUU");
1610  tarType[i]='U';
1611  }
1612  }
1613 
1614 
1615  for (i = 0; i < length-1; i++)
1616  {
1617  if(tarType[i]=='T' && tarType[i+1]=='S')
1618  {
1619  cpl_msg_warning(cpl_func,"Switching from T to S without U at "
1620  "frame %d", i);
1621  cpl_msg_warning(cpl_func,"Changing target type of frame %d and %d"
1622  " to %c", i, i+1, 'U');
1623  tarType[i]='U';
1624  CounterBad++;
1625  tarType[i+1]='U';
1626  CounterBad++;
1627  }
1628 
1629  if(tarType[i]=='S' && tarType[i+1]=='T')
1630  {
1631  cpl_msg_warning(cpl_func,"Switching from S to T without U at "
1632  "frame %d", i);
1633  cpl_msg_warning(cpl_func,"Changing target type of frame %d and %d"
1634  " to %c", i, i+1, 'U');
1635  tarType[i]='U';
1636  CounterBad++;
1637  tarType[i+1]='U';
1638  CounterBad++;
1639  }
1640 
1641  }
1642 
1643 
1644  for (i = 0; i < length; i++)
1645  {
1646  // Count number of Targets
1647  if (tarType[i] == 'T')
1648  {
1649  if (lastType == 'S')
1650  {
1651  sprintf (midiMessage, "Switching from S to T without U at frame %d. QCLOG", i);
1652  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1653  *error = 1;
1654  }
1655  if (lastShot == 'T')
1656  {
1657  sprintf (midiMessage, "Switching from T to T without S at frame %d. QCLOG", i);
1658  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1659  *error = 1;
1660  }
1661  T++;
1662  mask[i] = 'T';
1663  lastType = 'T';
1664  newPair = 0;
1665  }
1666  // Count number of Skys
1667  else if (tarType[i] == 'S')
1668  {
1669  if (lastType == 'T')
1670  {
1671  sprintf (midiMessage, "Switching from T to S without U at frame %d. QCLOG", i);
1672  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1673  *error = 1;
1674  }
1675  if (lastShot == 'S')
1676  {
1677  sprintf (midiMessage, "Switching from S to S without T at frame %d. QCLOG", i);
1678  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1679  *error = 1;
1680  }
1681  S++;
1682  mask[i] = 'S';
1683  lastType = 'S';
1684  newPair = 0;
1685  }
1686  else
1687  {
1688  mask[i] = 'U';
1689  if (lastType == 'T')
1690  {
1691  lastShot = 'T';
1692  foundT = 1;
1693  }
1694  if (lastType == 'S')
1695  {
1696  lastShot = 'S';
1697  foundS = 1;
1698  }
1699  lastType = 'U';
1700  if (newPair)
1701  start++;
1702  }
1703  // Check sizes and apply corrections
1704  if ((foundS && foundT) || (foundS && T && (i == length-1)) || (foundT && S && (i == length-1)))
1705  {
1706  end = i+1;
1707  if (S < T)
1708  min = S;
1709  else
1710  min = T;
1711 
1712  T = S = 0;
1713  for (j = start; j < end; j++)
1714  {
1715  if (mask[j] == 'T')
1716  {
1717  T++;
1718  if (T > min)
1719  {
1720  mask[j] = 'U';
1721  sprintf (midiMessage, "Chopping inconsistency. Found extra 'T' at frame %d. Corrected. QCLOG", j);
1722  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1723  }
1724  }
1725  else if (mask[j] == 'S')
1726  {
1727  S++;
1728  if (S > min)
1729  {
1730  mask[j] = 'U';
1731  sprintf (midiMessage, "Chopping inconsistency. Found extra 'S' at frame %d. Corrected. QCLOG", j);
1732  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1733  }
1734  }
1735  }
1736  T = S = 0;
1737  if (foundS && foundT)
1738  {
1739  newPair = 1;
1740  start = i;
1741  --i;
1742  }
1743  foundS = foundT = 0;
1744  }
1745  else if ((!foundS && T && (i == length-1)) || (!foundT && S && (i == length-1)))
1746  {
1747  for (j = start; j <= i; j++)
1748  {
1749  mask[j] = 'U';
1750  sprintf (midiMessage, "Chopping inconsistency. Found extra 'S' or 'T' at frame %d. Corrected. QCLOG", j);
1751  midiReportWarning (midiReportPtr, routine, __FILE__, __LINE__, midiMessage);
1752  }
1753  }
1754  }
1755 
1756  // Update tarType
1757  for (i = 0; i < length; i++)
1758  tarType[i] = mask[i];
1759 
1760  // Display new tarType
1761  if (diagnostic > 4)
1762  {
1763  for (i = 0; i < length; i++)
1764  {
1765  cpl_msg_info(cpl_func,"%4d %c \n", i, tarType[i]);
1766  fprintf (midiReportPtr, "%4d %c \n", i, tarType[i]);
1767  }
1768  }
1769 
1770  // Release memory
1771  free (mask);
1772 
1773  return CounterBad;
1774 }
1775 /*****************************************************************************/
1776