001    package util;
002    
003    import java.text.DecimalFormat;
004    import org.eso.fits.*;
005    import java.lang.*;
006    import java.util.*;
007    import java.io.*;
008    
009    import javax.swing.*;
010    import ui.recognizer.PlotFileFilter;
011    
012    /** Convert FITS from 2QZ format to one or more text files
013     *  @version 1.0 Oct 17 2003
014     *  @author  John Talbot
015     */
016    public class ConvertFits2qz {
017        /** Static method for converting FITS to text files.
018         *
019         *  @param argv   array of arguments i.e.  FITS files
020         */
021    
022    /**
023    *group of pixels | has number of pixels | one or more
024    *  continuous range of pixels | is a kind of | group of pixels
025    *  continuous range of pixels | has definition | A kind of group of pixels which are continuous
026    *  continuous range of pixels | has lower bound | given as an integer or wavelength
027    *  continuous range of pixels | has upper bound | given as an integer or wavelength
028    *    hole | is a kind of | continuous range of pixels
029    *    hole | has definition | A kind of continuous range of pixels with intensity value equal to -200
030    *    hole | has intensity value | -200
031    *    hole | is dealt with using the procedure | which depends the range of the hole
032    *      leading hole | is a kind of | hole
033    *      leading hole | has definition | A kind of hole located at the beginning of the pixel array
034    *      leading hole | has lower bound | beginning of the pixel array
035    *      leading hole | has upper bound | a given pixel
036    *      leading hole | is dealt with using the procedure | truncate the spectra range up to the first non-hole value
037    *      trailing hole | is a kind of | hole
038    *      trailing hole | has definition | A kind of hole located at the end of the pixel array
039    *      trailing hole | has lower bound | a given pixel
040    *      trailing hole | has upper bound | end of the pixel array
041    *      trailing hole | is dealt with using the procedure | truncate the spectra range down to the last non-hole value
042    *      internal hole | is a kind of | hole
043    *      internal hole | has definition | A kind of hole located within the non-hole pixel array
044    *      internal hole | has lower bound | a given pixel
045    *      internal hole | has upper bound | a higher pixel location than the lower bound
046    *      internal hole | is dealt with using the procedure | linear interpolation between the first non-hole value below lower bound and the first non-hole value above the upper bound
047    */
048    public static final double HOLE = -199;  // should be -200 but some values are like -199.9999
049    
050    /** truncate spectra range to non-hole values and only export non-hole intensities */
051    public static final boolean SKIP_HOLES = true;                 
052    
053    /** interpolate between the lower and upper bound of internal holes */
054    public static final boolean INTERPOLATE_INTERNAL_HOLES = true;
055         
056        public static void main(String[] argv) {
057    
058            if (argv.length < 1) {
059              javax.swing.filechooser.FileFilter filter = new PlotFileFilter("FITS Files", new String[] {"fits", "fit"});
060    
061              JFileChooser loadFileChooser = new JFileChooser();
062              loadFileChooser.setDialogTitle("Convert FITS files or directory");
063              loadFileChooser.setCurrentDirectory(new File("."));
064              loadFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
065              loadFileChooser.addChoosableFileFilter(filter);
066              loadFileChooser.setFileFilter(filter);
067    
068              JFrame f = new JFrame("Convert FITS files or directory");
069    
070              f.setSize(300, 150);
071              f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
072              f.pack();
073              f.setVisible(true);
074    
075              File file = null;
076              if (loadFileChooser.showOpenDialog(f) == JFileChooser.APPROVE_OPTION) {     // BUG: 'up' icon in file chooser is disabled
077                 file = loadFileChooser.getSelectedFile();
078              }
079              convertFiles(file);
080            } else {
081                for (int na = 0; na < argv.length; na++) {
082                  convertFiles(new File(argv[na]));
083                }
084            }
085            //TODO: handle command line arguments for (int na=0; na<argv.length; na++) {
086            System.exit(0);
087        }
088    
089      // Handle recursive directories
090      public static void convertFiles(File aFile) {
091        if (aFile == null) 
092          return;
093        else if (aFile.isDirectory()) {  // if File is a directory then process all files in that directory
094          System.out.println("Dir : " + aFile);
095          File[] files = aFile.listFiles();
096          for (int i = 0 ; i < files.length; i++) {
097            convertFiles(files[i]);
098          }
099        } else {
100          convertFile(aFile);
101        }
102      }
103    
104      public static void convertFile(File aFile) {
105        DecimalFormat xFormatter = new DecimalFormat("0.000");
106        DecimalFormat yFormatter = new DecimalFormat("0.000");
107        FitsFile file = null;
108        try {
109          file = new FitsFile(aFile);
110          String name = aFile.getName();
111          int noHDU = file.getNoHDUnits();
112          for (int i = 0; i < 1; i++) {
113            FitsHDUnit hdu = file.getHDUnit(i);
114            FitsHeader hdr = hdu.getHeader();
115            int noKw = hdr.getNoKeywords();
116            int type = hdr.getType();
117            int size = (int) hdr.getDataSize();
118            String fileName = name.split("fits")[0] + "txt";
119            FileWriter writer = new FileWriter(fileName);
120            System.out.println("Creating spectra " + fileName);
121            Enumeration enumeration = hdr.getKeywords();
122            while (enumeration.hasMoreElements()) {
123              FitsKeyword kw = (FitsKeyword) enumeration.nextElement();
124              writer.write("#" + kw.getName());
125              switch (kw.getType()) {
126              case FitsKeyword.COMMENT:
127                writer.write("(C) " + kw.getComment());
128                break;
129              case FitsKeyword.STRING:
130                writer.write("(S)= '" + kw.getString() + "'");
131                break;
132              case FitsKeyword.BOOLEAN:
133                writer.write("(B)= " + kw.getBool());
134                break;
135              case FitsKeyword.INTEGER:
136                writer.write("(I)= " + kw.getInt());
137                break;
138              case FitsKeyword.REAL:
139                writer.write("(R)= " + kw.getReal());
140                break;
141              case FitsKeyword.DATE:
142                writer.write("(D)= " + kw.getString());
143                break;
144              default:
145              }
146              if (0<kw.getComment().length() && (kw.getType()!=FitsKeyword.COMMENT)) {
147                writer.write(" / " + kw.getComment());
148              }
149              writer.write("\n");
150            }
151            if (type == Fits.IMAGE) {
152              FitsMatrix dm = (FitsMatrix) hdu.getData();
153              int naxis[] = dm.getNaxis();
154              double crval[] = dm.getCrval();
155              double crpix[] = dm.getCrpix();
156              double cdelt[] = dm.getCdelt();
157              int nv, off, npix;
158              int nval = dm.getNoValues();
159              if (0 < nval) {
160                int ncol = naxis[0];
161                int nrow = nval/ncol;
162                float data[] = new float[ncol];
163                off = 0;
164                nrow = 1;  // Only get first row
165                for (int nr = 0; nr < nrow; nr++) {
166                  try {
167                    dm.getFloatValues(off, ncol, data);
168                    if (INTERPOLATE_INTERNAL_HOLES) {  // linear interpolation internal holes
169                      boolean firstHole = true;
170                      boolean inHole = false;
171                      int hole_start = 0;
172                      int hole_end = 0;
173                      for (int n = 0; n < ncol; n++) {
174                        double val = data[n];
175                        if (firstHole && val < HOLE)  // ignore leading hole
176                           continue;
177                        else
178                           firstHole = false;
179                      
180                        if (!inHole && val < HOLE) {
181                          inHole = true;
182                          hole_start = n - 1;
183                        } else if(inHole && val > HOLE) {
184                          inHole = false;
185                          hole_end = n;
186                          if (hole_end != ncol - 1) {  // ignore trailing hole 
187                            // linear interpolation of this instance of internal hole
188                            double x1 = (double) hole_start;
189                            double x2 = (double) hole_end;
190                            double y1 = data[hole_start];
191                            double y2 = data[hole_end];
192                            double slope = (y2-y1)/(x2-x1);
193                            for (int j = 1; j < hole_end - hole_start; j++) {
194                              data[hole_start + j] = (float) (slope*((double)j) + y1);
195                            }
196                          }
197                        }
198                        
199                      }
200                    }
201                    
202                    // wavelength computation verified with FV fits viewer
203                    FitsKeyword kw = hdr.getKeyword("CD1_1");
204                    double deltaWavelength = kw.getReal();   //cdelt[0];
205                    double startWavelength = crval[0] - (crpix[0]-1)*deltaWavelength; 
206                    for (int n = 0; n < ncol; n++) {
207                      double val = data[n];
208                      // avoid floating point truncation error by not using  wavelength += deltaWavelength
209                      double wavelength = startWavelength + n*deltaWavelength;
210                      // don't export leading hole and trailing hole (truncate spectra range)
211                      if (!SKIP_HOLES || val > HOLE) {
212                        StringBuffer s = new StringBuffer(xFormatter.format(wavelength));
213                        s.append(" ");
214                        String y = yFormatter.format(val);
215                        s.append(y);
216                        s.append("\n");
217                        writer.write(s.toString());
218                      }
219                    }
220                  } catch (FitsException e) {
221                  }
222                  off += ncol;
223                }
224              }
225            }
226            if (writer != null) writer.close();
227    
228    
229    
230    
231          }
232          if (file != null) file.closeFile();
233        } catch (FitsException e) {
234          System.out.println("Error: is not a FITS file >" + aFile + "<");
235          return;
236        } catch (IOException e) {
237          System.out.println("Error: cannot open file >" + aFile + "<");
238          return;
239        }
240      }
241    }