vendredi 2 septembre 2016

ARAS dataBase

Hello,


ARAS is the Astronomical Ring for Access to Spectroscopy. It is an informal group of people set in 2003 after the pro/am astrophysics school of Oléron organized by CNRS and AUDE association

ARAS aims to promote cooperation between professional and amateur astronomers in the field of spectroscopy.

To this end, ARAS has prepared the following roadmap:
• Identify  centers  of  interest  for  spectroscopic  observation  which  could  lead  to  useful,  effective  and  motivating  cooperation  between  professional  and  amateur  astronomers.
• Help developping the tools required to transform this cooperation into action  (i.e.  by  publishing  spectrograph  building  plans,  organizing group  purchasing  to  reduce  costs,  developing  and  validating  observation  protocols,  managing  a  data  base,  identifying  available  resources  in  professional  observatories  (hardware,  observation  time),  etc.
• Develop  an  awareness  and  education  policy  for  amateur  astronomers  through  training  sessions,  the  organization  of  pro/am  seminars,  by  publishing  documents  (web  pages),  managing  a  forum,  etc.
• Encourage observers to use the spectrographs available in mission observatories and promote collaboration between experts, particularly variable star experts.
• Create a global observation network.


ARAS is first a front web page:
http://www.astrosurf.com/aras/

You will find there lot of ideas of projects to run with your astronomical spectrograph.
I would like to highlight two newsletters published on regular basis:
Be stars: http://www.astrosurf.com/aras/surveys/beactu/index.htm
Eruptive stars: http://www.astrosurf.com/aras/novae/InformationLetter/InformationLetter.html
(whose content is broader than simply eruptive stars!)


ARAS is also a discussion group on Yahoo group:
https://groups.yahoo.com/neo/groups/spectro-l/info

Alerts and request for observations are usually published on this discussion group.


For more permanent archive and more structured information, ARAS has also a forum:
http://www.spectro-aras.com/forum/

This is THE place for spectroscopy, to get ideas, latest campaign information, exchange with others... Well, not THE only one as Thomas Eversberg mentionned on the Spectro-L discussion group:

I take the liberty to mention the two most active other groups who do the same as ARAS including my personal impression about their activities.

SASER - the Southern Astro Spectroscopy Email Ring (http://saser.wholemeal.co.nz/)  is the only amateur-professional group in the south. The perform extremely well organized campaigns on a number of objects (e.g., O, Be and WR stars – pro-level). Neglecting the advantage to obtain data from the galactic center I experience an extremely well organized and coordinated team from (presently) New Zealand, Australia and Brazil. That means that these fellows can start COORDINATED observations within some hours over the (almost) entire southern hemisphere. The main SASER focus is on campaigns but technical issues are also discussed.

VdS Spectroscopy (http://spektroskopie.fg-vds.de/) is the German and from my knowledge the oldest amateur-professional group in the world. VdS organized a number of amateur-professional campaigns (e.g., O, Be and WR stars) plus observations of galaxies and nebulae. However, its main focus is on technical issues (pro-level) considering the respective discussions in its bilingual (German/English) forum and the weather conditions in Germany (that is why the group organized two extremely long amateur-professional campaigns on Tenerife). Twice a year  the group also publishes its (almost 25 year old) free online Journal SPEKTRUM as pdf which reflects ongoing work within the group. And every year there is a conference to discuss with others in person (2017 in Switzerland)

Some colleagues are active in ARAS, SASER and VdS, some in two of them but all groups are all working on a very high (partly professional) level.


For stars for which an observation campaign is clearly identified - ie: one or more amateur(s) is (are) willing to help validating the spectra and coordinating the observation AND one or more professional(s) astronomer(s) show(s) some interest - a database exists to collect and archive the spectra. This is the ARAS spectra dataBase:
http://www.astrosurf.com/aras/Aras_DataBase/DataBase.htm


François Teyssier has done a tremendous job (really tremendous!) in setting up the dataBase using Excel spreadsheets and maintaining it - alone - since the beginning.

I have volunteered long time ago to be of some assistance and be responsible for:
-VV Cep (or zeta Aurigae) type of stars; Ernst Pollman is very active to monitor VV Cep and
-LBV Luminous Blue Variable (mainly P Cygni) stars for which Ernst Pollman is very active in monitoring Halpha and HeI 6678 lines for exemple
-Micro Quasars (SS433, Cygnus X-1); Kathrine Blundell from Oxford is interested in such spectra and it is any fun to see such changes and so high velocities such as in the case of SS 433!

Truth is that I have not been very confortable in using Excel macros and prefered to write my own MatLab code to do the dataBase web pages. They don't look exactly the same as Excel's one but are close enough.

Process is now in place (finally, I can hear François sigh of relief!) to receive spectra, check them and update the web page/dataBase.

There are three web pages, one for each campaign/group:
VV Cep: http://www.astrosurf.com/aras/Aras_DataBase/VVCepStars.htm
LBV: http://www.astrosurf.com/aras/Aras_DataBase/LBV.htm
Micro Quasars: http://www.astrosurf.com/aras/Aras_DataBase/MicrosQuasars.htm


From a technical point of view, I use two scripts; they are given at the end of this blog for reference/archive.

Here is my process: fFirst I updated my local dataBase with the FITS file I receive. The FITS file should be compliant with BeSS format and the filename should follow some convention: asdb_NomObjet_aaaammdd_hhh

See for more details:
http://www.astrosurf.com/aras/Aras_DataBase/Usage.htm

If the spectrum is flux calibrated, I add 'flux' in the filename.
If the echelle spectrum if provided in a ZIP archive, I use the same file root name for both files. The ZIP can also contain a time serie for exemple.

I check them by comparing with the most recent spectrum (or the one closest to it) with a simple graph (I still need to write a third script to help me there but this task is fairly straight forward for the moment).
If I see something strange in the wavelength calibration, overall shape, etc... I put the spectrum aside and contact the observer.

I go in my local dataBase in the proper directory (LBV, VVCepStars, or microquasars) where I have added latest spectra and run dbFitsTable.m script after having changed the campaign by a group code (LBV, VVCep, SS433).

Then I can upload the new spectra, the associated graphs and the updated webpages on ARAS server.


You find the same pages as for the other campaigns with the list of targets with number of spectra, the first and last ones:


You also have for each target a table of all spectra with some information in a structured way:



If you left clic on the spectrum ID you will have a graph. If you right clic on the filename or the ZIP, you can save the spectrum on your hard drive:



But there is also a new feature with the last 10 spectra including a graph of the full specrum and a graph around Halpha/HeI6678 which allow a quick comparison with other spectra:



Olivier Thizy


Annexe 1: dbFitsTable.m
Code for dbFitsTable.m, release 1.0, my first version of the database for those stars:

% dbFitsTable.m
%
% Read spectra from the given directory and create thumbnails and HTML web pages for ARAS database
%
% v1.0 / 20160902 - used for the first release this format on ARAS server
%
% Olivier Thizy
%

clear;
clear all;

Group = 'VVCep'; % 'VVCep', 'LBV', 'SS433' (MicroQuasars) - CHOOSE THE GROUP BEFORE RUNNING dbFitsTable.m !!!
ARAS = true; % true if ARAS database, false if personal one
DisplayGraphs = false; % true to add graphs on web page, false otherwise (ARAS standard)
ReDoGraphs = false; % true to redo the graphs, false otherwise
NbLastSpectra = 10; % number of spectra to display in the last spectra HTML file
SearchSubDirectories = true;
Xlimit1 = 6500; % Wavelength limit for main graph, or -inf
Xlimit2 = 6700; % Wavelength limit for main graph, or -inf




if ARAS
    switch Group
        case 'VVCep'
            %%% IMPORTANT - CHANGE DIRECTORY & FILENAME HERE %%%
            BaseFilePath = 'D:\Aras_DataBase\VVCepStars\'; % Change depending on what campaign we work on !!!
            BaseFilePath2 = '.\VVCepStars\'; % Change depending on what campaign we work on !!!
            MainWebPage = '..\VVCepStars.htm'; % Change depending on what campaign we work on !!!
            CampaignTitle = 'VV Cep stars';
        case 'LBV'
            BaseFilePath = 'D:\Aras_DataBase\LBV\'; % Change depending on what campaign we work on !!!
            BaseFilePath2 = '.\LBV\'; % Change depending on what campaign we work on !!!
            MainWebPage = '..\LBV.htm'; % Change depending on what campaign we work on !!!
            CampaignTitle = 'Luminous Blue Variable stars';
        case 'SS433'
            BaseFilePath = 'D:\Aras_DataBase\Microquasars\'; % Change depending on what campaign we work on !!!
            BaseFilePath2 = '.\Microquasars\'; % Change depending on what campaign we work on !!!
            MainWebPage = '..\MicrosQuasars.htm'; % Change depending on what campaign we work on !!!
            CampaignTitle = 'Micro Quasars';
    end
    MainTitle = 'A.R.A.S. Spectral dataBase';
    MainURL = '..\DataBase.htm';
    MainURL2 = '.\DataBase.htm';
    ObjectName{1} = 'VV Cep';
    webFileName{1} = 'VVCep.htm';
    PreviousURL{1} = '..\VVCepStars.htm';
    webTitle{1} = 'VV Cep stars: VV Cep';
    ObjectRA{1} = '21 56 39.1';
    ObjectDec{1} = '+63 37 32';
    ObjectRem{1} = 'Mag V = 4.9';
    ObjectName{2} = '31 Cyg';
    webFileName{2} = '31Cyg.htm';
    PreviousURL{2} = '..\VVCepStars.htm';
    webTitle{2} = 'VV Cep stars: 31 Cyg';
    ObjectRA{2} = '20 13 37.9';
    ObjectDec{2} = '+46 44 28.8';
    ObjectRem{2} = 'Mag V = 3.8';
    ObjectName{3} = '32 Cyg';
    webFileName{3} = '32Cyg.htm';
    PreviousURL{3} = '..\VVCepStars.htm';
    webTitle{3} = 'VV Cep stars: 32 Cyg';
    ObjectRA{3} = '20 15 28.3';
    ObjectDec{3} = '+47 42 51.2';
    ObjectRem{3} = 'Mag V = 4.0';
    ObjectName{4} = 'zet Aur';
    webFileName{4} = 'zetAur.htm';
    PreviousURL{4} = '..\VVCepStars.htm';
    webTitle{4} = 'VV Cep stars: zet Aur';
    ObjectRA{4} = '';
    ObjectDec{4} = '';
    ObjectRem{4} = '';
    ObjectName{5} = 'P Cyg';
    PreviousURL{5} = '..\LBV.htm';
    webFileName{5} = 'PCyg.htm';
    webTitle{5} = 'Luminous Blue Variables: P Cygni';
    ObjectRA{5} = '20 17 47.2';
    ObjectDec{5} = '+38 01 58';
    ObjectRem{5} = '';
    ObjectName{6} = 'SS 433';
    webFileName{6} = 'ss433.htm';
    PreviousURL{6} = '..\MicrosQuasars.htm';
    webTitle{6} = 'Micro Quasars: SS 433';
    ObjectRA{6} = '';
    ObjectDec{6} = '';
    ObjectRem{6} = '';
    ObjectName{7} = 'Cygnus X-1';
    webFileName{7} = 'cygnusx-1.htm';
    PreviousURL{7} = '..\MicrosQuasars.htm';
    webTitle{7} = 'Micro Quasars: Cygnus X-1';
    ObjectRA{7} = '';
    ObjectDec{7} = '';
    ObjectRem{7} = '';
    NbObjects = 7;
    ObjectName{NbObjects+1} = 'Unknown';
    PreviousURL{NbObjects+1} = '../unknown.htm';
    webFileName{NbObjects+1} = 'unknown.htm';
    webTitle{NbObjects+1} = 'Unknown objects/campaign ???';
    for jj = 1:(NbObjects+1)
        CountObject{jj} = 0;
    end
else
    MainURL = 'index.html';
    MainTitle = 'Personal astronomical spectroscopical dataBase';
    BaseFilePath = 'D:\Acquisitions\00_MySpectroDataBase\DATABASE\THIZY\Observatoire Belle Etoile';
end

location = '.\';


% TO DO:
% ======
%
% ==> Create FITS header only with updated/coherent data (used for faster
% processing after)
%
% ==> Separate web page with latest spectra (same as ARASBeAm (monitoring)
%
% ==> Separate web page with last spectrum and ID for the star + info on
% the campaign (comments).
%
% ==> Split pages per objects + sort data by date
%
% ==> add to the data structure (based on standardised object name):
% --> ARASGroup: Eruptive stars, miscellaneous...
% --> ARASGroupDir for ARAS database directory
% --> ARASSubGroup: MicroQuasars, HMBX, AGN, B[e] stars, VV CEp stars...
% --> ARASSubGroupDir for ARAS database directory
%

% Create list of FITS files in the directpry & subdirectories
ds = datastore(location,'Type','image','IncludeSubfolders',SearchSubDirectories,'FileExtensions',{'.fit','.fits','.FIT','.FITS'});
% if multiple directories, can use {location1,location2,location3} syntax


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Read and process all FITS files headers (without changing them)
% Then print all details in a single HTML web page/table
% TO DO: !!! SORT LINES BY CATEGORY (to be created) / OBJECT / DATE !!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
NbFiles = 0;
for i = 1:length(ds.Files)
    fName = char(ds.Files(i));
    [filepath,filename,fileext] = fileparts(fName);

    % Manage when filename includes unvalid characters for fitsio routine
    if (max(size(strfind(fName,'('))) ~= 0) || (max(size(strfind(fName,')'))) ~= 0)
        fNameValid = 0;
        copyfile(fName,'otz_tmp.fit');
        fName = 'otz_tmp.fit';
    else fNameValid = 1;
    end
    data = rfitsinfo(fName);     % Read the ith image & get FITS details

    if data.Valid == 1
        NbFiles = NbFiles + 1;
        UnsortedKey(NbFiles,1) = NbFiles;
        UnsortedKey(NbFiles,2) = data.CalcJD;
        dataBase{NbFiles} = data;
        dataBase{NbFiles}.fname = char(ds.Files(i));
        dataBase{NbFiles}.filepath = filepath;
        dataBase{NbFiles}.filename = filename;
        dataBase{NbFiles}.fileext = fileext;
        dataBase{NbFiles}.fNameValid = fNameValid;
        if strcmp(filepath, BaseFilePath)
            dataBase{NbFiles}.shortfilepath = '.\';
        else
            dataBase{NbFiles}.shortfilepath = strcat('.\',filepath(size(BaseFilePath,2)+1:size(filepath,2)));
        end
        GraphfName = strcat(dataBase{NbFiles}.shortfilepath,'\',filename,'.png');
        dataBase{NbFiles}.GraphfName = GraphfName;
        FullGraphfName = strcat(dataBase{NbFiles}.shortfilepath,'\',filename,'_FULL.png');
        dataBase{NbFiles}.FullGraphfName = FullGraphfName;

        if ARAS
            Tmp = true;
            for jj = 1:NbObjects
                if strcmp(data.Object,ObjectName{jj})
                    data.NoObject = jj;
                    CountObject{jj} = CountObject{jj} + 1;
                    Tmp = false;
                end
            end
            if Tmp
                    data.NoObject = NbObjects+1;               
                    CountObject{NbObjects+1} = CountObject{NbObjects+1} + 1;
            end
        end
        UnsortedKey(NbFiles,3) = data.NoObject;
    end
end


SortedKey = sortrows(UnsortedKey,[3 2]); % Sort by Object ID then date

if ARAS
    Nbend = NbFiles;
    for jj = NbObjects+1:-1:1
        if CountObject{jj} ~= 0
            FullwebFileName{jj} = [location webFileName{jj}];
           
            Nend{jj} = Nbend; % Id # of last spectrum of this Object (=most recent date)
            Nstart{jj} = Nbend - CountObject{jj} + 1; % Id # of first spectrum of this Object (=oldest date)
            Nbend = Nstart{jj} - 1; % for next Object...

            NLastSpectra{jj} = min(CountObject{jj}, NbLastSpectra);
            LastStart{jj} = Nend{jj}-NLastSpectra{jj} + 1;
            FullLastFileName{jj} = [location 'last_' webFileName{jj}];
           
            % Open text file for HTML web page
            fileID{jj} = fopen(FullwebFileName{jj},'w');
           
            %%% HTML header %%%  / all spectra list
            fprintf(fileID{jj},'<!DOCTYPE html>\r\n');
            fprintf(fileID{jj},'<HTML>\r\n');
            fprintf(fileID{jj},'<HEAD><TITLE>%s</TITLE></HEAD>\r\n',webTitle{jj});
            fprintf(fileID{jj},'<BODY bgcolor="#ffffff" text="#000099" link="#660066" vlink="#cc99cc" alink="#33ff99">');
           
            % Table style / all spectra list
            fprintf(fileID{jj},'<style>\r\n');
            fprintf(fileID{jj},'table, th, td {\r\n');
            fprintf(fileID{jj},'    border: 1px solid black;\r\n');
            fprintf(fileID{jj},'    border-collapse: collapse;\r\n');
            fprintf(fileID{jj},'}\r\n');
            fprintf(fileID{jj},'th, td {\r\n');
            fprintf(fileID{jj},'    padding: 5px;\r\n');
            fprintf(fileID{jj},'}\r\n');
            fprintf(fileID{jj},'</style>\r\n');
           
            % TITLE & top of the page / all spectra list
            fprintf(fileID{jj},'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',MainTitle);
            fprintf(fileID{jj},'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',webTitle{jj});
            fprintf(fileID{jj},'<CENTER><B><I>Send spectra to: <A HREF="mailto:thizy@free.fr">Olivier THIZY</A></I></B></CENTER>');
            fprintf(fileID{jj},'<P>\r\n');
            fprintf(fileID{jj},'Nb of spectra: %d\r\n', CountObject{jj});
            fprintf(fileID{jj},'<BR>\r\n');
            fprintf(fileID{jj},'First date: %sT%s (JD: %0.5f) by %s (%s)\r\n', datestr(dataBase{SortedKey(Nstart{jj},1)}.Date,'yyyy/mm/dd'), datestr(dataBase{SortedKey(Nstart{jj},1)}.Date,'HH:MM:SS.FFF'), dataBase{SortedKey(Nstart{jj},1)}.CalcJD, dataBase{SortedKey(Nstart{jj},1)}.ObserverCode, dataBase{SortedKey(Nstart{jj},1)}.Observer);
            fprintf(fileID{jj},'<BR>\r\n');
            fprintf(fileID{jj},'Last date: %sT%s (JD: %0.5f) by %s (%s)\r\n', datestr(dataBase{SortedKey(Nend{jj},1)}.Date,'yyyy/mm/dd'), datestr(dataBase{SortedKey(Nend{jj},1)}.Date,'HH:MM:SS.FFF'), dataBase{SortedKey(Nend{jj},1)}.CalcJD, dataBase{SortedKey(Nend{jj},1)}.ObserverCode, dataBase{SortedKey(Nend{jj},1)}.Observer);
            fprintf(fileID{jj},'<P>\r\n');
            fprintf(fileID{jj},'Last spectra details: <A HREF="%s">%s</A>\r\n', FullLastFileName{jj}, FullLastFileName{jj});
            fprintf(fileID{jj},'<BR>\r\n');
            fprintf(fileID{jj},'Campaign: <A HREF="%s">%s</A>\r\n', PreviousURL{jj}, PreviousURL{jj});
            fprintf(fileID{jj},'<BR>\r\n');
            fprintf(fileID{jj},'ARAS dataBase: <A HREF="%s">%s</A>\r\n', MainURL, MainURL);
            fprintf(fileID{jj},'<BR><BR><P><P>\r\n');
           
            % Beginning of the spectra TABLE
            fprintf(fileID{jj},'<CENTER><TABLE>\r\n');
           
           
            %%% FIRST ROW: title %%%
            fprintf(fileID{jj},'<TR>\r\n');
           
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            if DisplayGraphs == 0;
                fprintf(fileID{jj},'#');
            else
                fprintf(fileID{jj},'Preview');
            end
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Date');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Time(UT)');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'J.D. mid');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            %fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            %fprintf(fileID{jj},'Exposure(s)');
            %fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Obs.');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Site');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Instrument');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'R');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'L_min');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'L_max');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Exp.(s)');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'File');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'Flux');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileID{jj},'ZIP?');
            fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            %fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
            %fprintf(fileID{jj},'Directory');
            %fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
           
            if jj == (NbObjects+1)
                fprintf(fileID{jj},'<TD><B><CENTER>\r\n');
                fprintf(fileID{jj},'Object');
                fprintf(fileID{jj},'</CENTER></B></TD>\r\n');
            end
           
            fprintf(fileID{jj},'</TR>\r\n');
            % end of ROW above
           
           
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % Main web page with all spectra but no graphics displayed
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            for index = Nend{jj}:-1:Nstart{jj}
                i = SortedKey(index,1);
               
                % Plot thumbnail of the spectrum graph (TO BE IMPROVED)
                if isempty (dir(dataBase{i}.GraphfName)) || isempty (dir(dataBase{i}.FullGraphfName)) || ReDoGraphs
                    % Graph using full spectral domain
                    plot(dataBase{i}.Wavelength, dataBase{i}.Intensity, 'r');
                    Titre1 = ['\fontsize{10}', dataBase{i}.Object, ' / ',dataBase{i}.ObserverCode, ' @ ', dataBase{i}.SiteCode];
                    SubTitle = sprintf('JD: %0.5f [%0.0fs]', dataBase{i}.CalcJD, dataBase{i}.ExpTimeTotal);
                    Titre2 = ['\fontsize{8}', SubTitle];
                    title({Titre1 ; Titre2});
                    xlabel('Wavelenght in Â');
                    x_limit = [Xlimit1 Xlimit2];
                    xlim(x_limit)
                    ylabel('Relative flux');
                    saveas(gca, dataBase{i}.GraphfName, 'png');
                   
                    % Zoom on Halpha and around...
                    plot(dataBase{i}.Wavelength, dataBase{i}.Intensity, 'r');
                    Titre1 = ['\fontsize{10}', dataBase{i}.Object, ' / ',dataBase{i}.ObserverCode, ' @ ', dataBase{i}.SiteCode];
                    SubTitle = sprintf('JD: %0.5f [%0.0fs]', dataBase{i}.CalcJD, dataBase{i}.ExpTimeTotal);
                    Titre2 = ['\fontsize{8}', SubTitle];
                    title({Titre1 ; Titre2});
                    xlabel('Wavelenght in Â');
                    x_limit = [-inf inf];
                    xlim(x_limit)
                    ylabel('Relative flux');
                    saveas(gca, dataBase{i}.FullGraphfName, 'png');
                end
               
                %%% One row per spectrum... %%%
                fprintf(fileID{jj},'<TR>\r\n');
               
                % Thumbnails (FULL spectrum)if DisplayGraphs is set as true
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                if DisplayGraphs
                    fprintf(fileID{jj},'<A HREF=\"%s\\%s%s\"><IMG SRC=\"%s\" NAME=\"%s\" ALIGN=BOTTOM WIDTH=400 HEIGHT=280 BORDER=0></A>', dataBase{i}.shortfilepath, dataBase{i}.filename, dataBase{i}.fileext, dataBase{i}.GraphfName, dataBase{i}.filename);
                else
                    fprintf(fileID{jj},'<A HREF=\"%s\">%d</A>', dataBase{i}.FullGraphfName, index);
                end
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%s', datestr(dataBase{i}.Date,'yyyy/mm/dd'));
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%s', datestr(dataBase{i}.Date,'HH:MM:SS.FFF'));
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                %fprintf(fileID{jj},'<TD><CENTER>\r\n');
                %fprintf(fileID{jj},'%s', datestr(dataBase{i}.DateEnd,'HH:MM:SS.FFF'));
                %fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%0.5f', dataBase{i}.CalcJD);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%s', dataBase{i}.ObserverCode);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%s', dataBase{i}.SiteCode);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%s', dataBase{i}.Instrument);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%6.0f', dataBase{i}.Resolution);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%4.0f', dataBase{i}.WaveOrigin);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%4.0f', dataBase{i}.WaveMax);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'%0.0f', dataBase{i}.ExpTimeTotal);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                fprintf(fileID{jj},'<A HREF=\"%s\\%s%s\">%s%s</A>', dataBase{i}.shortfilepath, dataBase{i}.filename, dataBase{i}.fileext, dataBase{i}.filename, dataBase{i}.fileext);
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                if strfind(dataBase{i}.filename,'flux') >= 0
                    fprintf(fileID{jj},'yes');
                end
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileID{jj},'<TD><CENTER>\r\n');
                ZIPfName = strcat(dataBase{i}.filepath,'\\',dataBase{i}.filename,'.zip');
                if ~isempty (dir(ZIPfName))
                    fprintf(fileID{jj},'<A HREF=\"%s\\%s.zip\">ZIP</A>', dataBase{i}.shortfilepath, dataBase{i}.filename);
                end
                fprintf(fileID{jj},'</CENTER></TD>\r\n');
               
                %    fprintf(fileID{jj},'<TD><CENTER>\r\n');
                %    fprintf(fileID{jj},'%s\\', dataBase{i}.filepath);
                %    fprintf(fileID{jj},'</CENTER></TD>\r\n');

                if jj == (NbObjects+1)
                    fprintf(fileID{jj},'<TD><CENTER>\r\n');
                    fprintf(fileID{jj},'%s', dataBase{i}.Object);
                    fprintf(fileID{jj},'</CENTER></TD>\r\n');
                end
               
                fprintf(fileID{jj},'</TR>\r\n');
               
                % end of ROW above
               
            end
           
            %%% HTML end of file %%%
            fprintf(fileID{jj},'</CENTER></TABLE>\r\n');
            fprintf(fileID{jj},'</BODY>\r\n');
            fprintf(fileID{jj},'</HTML>\r\n');
           
            % and close the main file...
            fclose(fileID{jj});
           
           
           
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % Last spectra web page
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
           
            % Open text file for HTML web page
            fileIDLast{jj} = fopen(FullLastFileName{jj},'w');
           
            %%% HTML header %%% / Last X spectra displayed
            fprintf(fileIDLast{jj},'<!DOCTYPE html>\r\n');
            fprintf(fileIDLast{jj},'<HTML>\r\n');
            fprintf(fileIDLast{jj},'<HEAD><TITLE>%s</TITLE></HEAD>\r\n',webTitle{jj});
            fprintf(fileIDLast{jj},'<BODY bgcolor="#ffffff" text="#000099" link="#660066" vlink="#cc99cc" alink="#33ff99">');
           
            % Table style / Last X spectra displayed
            fprintf(fileIDLast{jj},'<style>\r\n');
            fprintf(fileIDLast{jj},'table, th, td {\r\n');
            fprintf(fileIDLast{jj},'    border: 1px solid black;\r\n');
            fprintf(fileIDLast{jj},'    border-collapse: collapse;\r\n');
            fprintf(fileIDLast{jj},'}\r\n');
            fprintf(fileIDLast{jj},'th, td {\r\n');
            fprintf(fileIDLast{jj},'    padding: 5px;\r\n');
            fprintf(fileIDLast{jj},'}\r\n');
            fprintf(fileIDLast{jj},'</style>\r\n');
           
            % TITLE & top of the page / Last X spectra displayed
            fprintf(fileIDLast{jj},'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',MainTitle);
            fprintf(fileIDLast{jj},'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',webTitle{jj});
            fprintf(fileIDLast{jj},'<CENTER><H1><B>Last %d Spectra (by acquisition date)</B></H1></CENTER>\r\n', NLastSpectra{jj});
            fprintf(fileIDLast{jj},'<CENTER><B><I>Contact: <A HREF="mailto:thizy@free.fr">Olivier THIZY</A></I></B></CENTER>');
            fprintf(fileIDLast{jj},'<P>\r\n');
            fprintf(fileIDLast{jj},'Nb of spectra: %d / %d\r\n', NLastSpectra{jj}, CountObject{jj});
            fprintf(fileIDLast{jj},'<P>\r\n');
            fprintf(fileIDLast{jj},'Back to spectra database: <A HREF="%s">%s</A>\r\n', FullwebFileName{jj}, FullwebFileName{jj});
            fprintf(fileIDLast{jj},'<BR><BR><P><P>\r\n');
           
            % Beginning of the spectra TABLE
            fprintf(fileIDLast{jj},'<CENTER><TABLE>\r\n');
           
            %%% FIRST ROW: title %%%
            fprintf(fileIDLast{jj},'<TR>\r\n');
            fprintf(fileIDLast{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileIDLast{jj},'full spectrum preview');
            fprintf(fileIDLast{jj},'</CENTER></B></TD>\r\n');
            fprintf(fileIDLast{jj},'<TD><B><CENTER>\r\n');
            fprintf(fileIDLast{jj},'preview around Halpha');
            fprintf(fileIDLast{jj},'</CENTER></B></TD>\r\n');
            fprintf(fileIDLast{jj},'<TD><B>\r\n');
            fprintf(fileIDLast{jj},'Spectrum details');
            fprintf(fileIDLast{jj},'</B></TD>\r\n');
           
            fprintf(fileIDLast{jj},'</TR>\r\n');
           
            for index = Nend{jj}:-1:LastStart{jj}
                i = SortedKey(index,1);
               
                %%% One row per spectrum... %%%
                fprintf(fileIDLast{jj},'<TR>\r\n');
               
                % Thumbnails of FULL spectrum & zoom on Halpha
                fprintf(fileIDLast{jj},'<TD><CENTER>\r\n');
                fprintf(fileIDLast{jj},'<A HREF=\"%s\\%s%s\"><IMG SRC=\"%s\" NAME=\"%s\" ALIGN=BOTTOM WIDTH=600 HEIGHT=400 BORDER=0></A>', dataBase{i}.shortfilepath, dataBase{i}.filename, dataBase{i}.fileext, dataBase{i}.FullGraphfName, dataBase{i}.filename);
                fprintf(fileIDLast{jj},'</CENTER></TD>\r\n');
                fprintf(fileIDLast{jj},'<TD><CENTER>\r\n');
                fprintf(fileIDLast{jj},'<A HREF=\"%s\\%s%s\"><IMG SRC=\"%s\" NAME=\"%s\" ALIGN=BOTTOM WIDTH=600 HEIGHT=400 BORDER=0></A>', dataBase{i}.shortfilepath, dataBase{i}.filename, dataBase{i}.fileext, dataBase{i}.GraphfName, dataBase{i}.filename);
                fprintf(fileIDLast{jj},'</CENTER></TD>\r\n');
               
                fprintf(fileIDLast{jj},'<TD>\r\n');
               
               
                fprintf(fileIDLast{jj},'Object: <B><I>%s</I></B><BR>\r\n', dataBase{i}.Object);
                fprintf(fileIDLast{jj},'Date: %s, from ', datestr(dataBase{i}.Date,'yyyy/mm/dd'));
                fprintf(fileIDLast{jj},'%s to ', datestr(dataBase{i}.Date,'HH:MM:SS.FFF'));
                fprintf(fileIDLast{jj},'%s<BR>\r\n', datestr(dataBase{i}.DateEnd,'HH:MM:SS.FFF'));
                fprintf(fileIDLast{jj},'Julian Date (calc.): %0.5f<BR>\r\n', dataBase{i}.CalcJD);
                fprintf(fileIDLast{jj},'Exposure: %0.0f<BR>\r\n', dataBase{i}.ExpTimeTotal);
                fprintf(fileIDLast{jj},'Taken by: <B>%s</B> (%s)<BR>\r\n', dataBase{i}.ObserverCode, dataBase{i}.Observer);
                fprintf(fileIDLast{jj},'Location: <B>%s</B> (%s)<BR>\r\n', dataBase{i}.SiteCode, dataBase{i}.SiteObs);
                fprintf(fileIDLast{jj},'Instrument: %s (R=%6.0f)<BR>\r\n', dataBase{i}.Instrument, dataBase{i}.Resolution);
                fprintf(fileIDLast{jj},'Spectral domain: %4.0f - %4.0f<BR>\r\n', dataBase{i}.WaveOrigin, dataBase{i}.WaveMax);
                fprintf(fileIDLast{jj},'<P>Spectrum file: <A HREF=\"%s\\%s%s\">%s%s</A>\r\n', dataBase{i}.shortfilepath, dataBase{i}.filename, dataBase{i}.fileext, dataBase{i}.filename, dataBase{i}.fileext);
                ZIPfName = strcat(dataBase{i}.filepath,'\\',dataBase{i}.filename,'.zip');
                if ~isempty (dir(ZIPfName))
                    fprintf(fileIDLast{jj},' (<A HREF=\"%s\\%s.zip\">ZIP file</A>)<P>\r\n', dataBase{i}.shortfilepath, dataBase{i}.filename);
                end
               
                fprintf(fileIDLast{jj},'</CENTER></TD>\r\n');
                fprintf(fileIDLast{jj},'</TR>\r\n');
                % end of ROW above
               
            end
           
            fprintf(fileIDLast{jj},'</CENTER></TABLE>\r\n');
            fprintf(fileIDLast{jj},'</BODY>\r\n');
            fprintf(fileIDLast{jj},'</HTML>\r\n');
           
            % and close the files
            fclose(fileIDLast{jj});
        end
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Campaign web page
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Open text file for HTML web page
fileIDCampaign = fopen(MainWebPage,'w');

%%% HTML header %%% / Last X spectra displayed
fprintf(fileIDCampaign,'<!DOCTYPE html>\r\n');
fprintf(fileIDCampaign,'<HTML>\r\n');
fprintf(fileIDCampaign,'<HEAD><TITLE>%s</TITLE></HEAD>\r\n',MainTitle);
fprintf(fileIDCampaign,'<BODY bgcolor="#ffffff" text="#000099" link="#660066" vlink="#cc99cc" alink="#33ff99">');

% Table style / Last X spectra displayed
fprintf(fileIDCampaign,'<style>\r\n');
fprintf(fileIDCampaign,'table, th, td {\r\n');
fprintf(fileIDCampaign,'    border: 1px solid black;\r\n');
fprintf(fileIDCampaign,'    border-collapse: collapse;\r\n');
fprintf(fileIDCampaign,'}\r\n');
fprintf(fileIDCampaign,'th, td {\r\n');
fprintf(fileIDCampaign,'    padding: 5px;\r\n');
fprintf(fileIDCampaign,'}\r\n');
fprintf(fileIDCampaign,'</style>\r\n');

% TITLE & top of the page / Last X spectra displayed
fprintf(fileIDCampaign,'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',MainTitle);
fprintf(fileIDCampaign,'<CENTER><H1><B>%s</B></H1></CENTER>\r\n',CampaignTitle);
fprintf(fileIDCampaign,'<CENTER><B><I>Contact: <A HREF="mailto:thizy@free.fr">Olivier THIZY</A></I></B></CENTER>');
fprintf(fileIDCampaign,'<P>\r\n');
NbStars = 0;
for jj=1:(NbObjects+1)
    if CountObject{jj} ~= 0
        NbStars = NbStars + 1;
    end
end
fprintf(fileIDCampaign,'Nb of stars: %d<BR>\r\n', NbStars);
fprintf(fileIDCampaign,'Nb of spectra: %d\r\n', NbFiles);
fprintf(fileIDCampaign,'<P>\r\n');
fprintf(fileIDCampaign,'Back to spectra database: <A HREF="%s">%s</A>\r\n', MainURL2, MainURL2);
fprintf(fileIDCampaign,'<BR><BR><P><P>\r\n');

% Beginning of the spectra TABLE
fprintf(fileIDCampaign,'<CENTER><TABLE>\r\n');

%%% FIRST ROW: title %%%
fprintf(fileIDCampaign,'<TR>\r\n');
fprintf(fileIDCampaign,'<TD><B><CENTER>\r\n');
fprintf(fileIDCampaign,'ID');
fprintf(fileIDCampaign,'</CENTER></B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B><CENTER>\r\n');
fprintf(fileIDCampaign,'Name');
fprintf(fileIDCampaign,'</CENTER></B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'AD');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'Dec');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'Nb Spectra');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'First');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'Last');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'Days since last');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'<TD><B>\r\n');
fprintf(fileIDCampaign,'Comment');
fprintf(fileIDCampaign,'</B></TD>\r\n');
fprintf(fileIDCampaign,'</TR>\r\n');


NbStars = 0;
for jj=1:NbObjects
    if CountObject{jj} ~= 0
        NbStars = NbStars + 1;
        fprintf(fileIDCampaign,'<TR>\r\n');
        fprintf(fileIDCampaign,'<TD><B><CENTER>\r\n');
        fprintf(fileIDCampaign,'%d', NbStars);
        fprintf(fileIDCampaign,'</CENTER></B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B><CENTER>\r\n');
        fprintf(fileIDCampaign,'<A HREF="%s%s">%s</A>', BaseFilePath2, webFileName{jj}, ObjectName{jj});
        fprintf(fileIDCampaign,'</CENTER></B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%s', ObjectRA{jj});
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%s', ObjectDec{jj});
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%d', CountObject{jj});
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%sT%s (JD: %0.5f) by %s (%s)\r\n', datestr(dataBase{SortedKey(Nstart{jj},1)}.Date,'yyyy/mm/dd'), datestr(dataBase{SortedKey(Nstart{jj},1)}.Date,'HH:MM:SS'), dataBase{SortedKey(Nstart{jj},1)}.CalcJD, dataBase{SortedKey(Nstart{jj},1)}.ObserverCode, dataBase{SortedKey(Nstart{jj},1)}.Observer);
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%sT%s (JD: %0.5f) by %s (%s)\r\n', datestr(dataBase{SortedKey(Nend{jj},1)}.Date,'yyyy/mm/dd'), datestr(dataBase{SortedKey(Nend{jj},1)}.Date,'HH:MM:SS'), dataBase{SortedKey(Nend{jj},1)}.CalcJD, dataBase{SortedKey(Nend{jj},1)}.ObserverCode, dataBase{SortedKey(Nend{jj},1)}.Observer);
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'...');
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'<TD><B>\r\n');
        fprintf(fileIDCampaign,'%s', ObjectRem{jj});
        fprintf(fileIDCampaign,'</B></TD>\r\n');
        fprintf(fileIDCampaign,'</TR>\r\n');
    end
end

fprintf(fileIDCampaign,'</CENTER></TABLE>\r\n');
fprintf(fileIDCampaign,'</BODY>\r\n');
fprintf(fileIDCampaign,'</HTML>\r\n');

fclose(fileIDCampaign);

display('That''s all folks !');
%%% That's all folks !



Annexe 2: rfitsinfo.m
This code use the rfitsinfo.m routine which is here:

function Header=rfitsinfo(File)

% RFITSINFO    Read FITS file header
%    Specific for astronomical spectra, mainly amateur ones
%  
%
%    RFITSINFO('file') reads a file written in FITS format and returns
%    all the relevant information in the header.
%
% v1.0 / 20160901 (c) Olivier Thizy
% Version used for v1 of ARAS dataBase using MatLab
%

% TO DO:
% ======
%
% ==> Heliocentric JD calculation
% using the astronomy & astrophysics package for Matlab (Ofek 2014)
% Cf: http://adsabs.harvard.edu/abs/2014ascl.soft07005O
%
% Pour VV Cep par exemple:
% ra = (21+(56+39.14385/60)/60)/12*pi
% dec = (63+(37+32.0174/60)/60)/180*pi
% jd = julian date
% [OutJD,ObjVel] = hjd(jd,[ra dec],'hh')
% showresult = sprintf('%0.6f',OutJD)
%
% ==> Calculate Heliocentric RV correction
% (to be done in rfitsinfo ?)
%
% ==> object name conversion & RA/DEC list
% *** ARASstars: table listing stars with key infos:VV Cep, RA, Dec, Vmag,
% SpType, ARASGroup, ARASSubGroup... (ext. TEXT file?)
% *** ARASstarsEQ: table of aliases for stars/objects; ex: VV Cep, VV_Cep,
% vvcep...  (ext. TEXT file?)
% Change the ObsCode conversion using a table structure (ext. TEXT file?)
% Change the ObsSite conversion using a table structure (ext. TEXT file?)
% Add in output data structure:
% --> RA, RA_d, RA_m, RA_s
% --> DEC, DEC_d, DEC_m, DEC_s
% --> Vmag, SpecType
%


H=fitsinfo(File);
Data = fitsread(File);
%Header.filename = File;


% searching for key header values
if max(size(H.Contents)) == 1
    kwd = H.PrimaryData.Keywords ;
elseif max(size(H.Contents)) > 3
    kwd = [H.PrimaryData.Keywords;H.Image(max(size(H.Contents))-2).Keywords];
else
    kwd = H.PrimaryData.Keywords ;
end

HeaderMax = max(size(kwd));

% Set criteria to 0; will be set to 1 when keyword is found...
WaveOrigin = 0;
Dispersion = 0;
Object = 0;
Date = 0;
DateEnd = 0;
JD = 0;
CalcJD = 0;
MidHJD = 0;
Exposure = 0;
ExpTimeTotal = 0;
Observer = 0;
Site = 0;
Instrument = 0;
NAXIS1 = 0;
Resolution = 0;

% Extrait certaines données de l'entèete fit
for l=1:HeaderMax
    k = kwd{l,1};
    kc = kwd{l,2};
    kt = kwd{l,3};
   
    switch k
    % CALIBRATION & REDUCTION data
    case 'NAXIS1'
        Header.NAXIS1 = kwd {l,2};
        NAXIS1= 1;
    case 'CRVAL1'
        Header.WaveOrigin = kwd {l,2};
        WaveOrigin = 1;
    case 'CDELT1'
        Header.Dispersion = kwd {l,2};
        Dispersion = 1;
    case 'BSS-VHEL'
        Header.VHel = kwd {l,2};
       
    % OBJECT data
    case {'OBJNAME', 'OBJECT'}
        Header.Object = kwd {l,2};
        Header.ObjName = kwd {l,2}; % Original name from FITS file
        Object = 1;
        switch Header.Object % Convert Object name to standard name for more consistent display/use
            case {'PCyg', 'p_cygni','P Cyg', 'pcyg', 'p cyg', '34 cyg', '34 Cyg', '34_cyg', '34_Cyg', '               P Cyg', 'P CYG'}
                Header.Object = 'P Cyg';
                Header.Campaign = 'LBV';
            case {'SS443','SS433', 'SS 433', '01_ss433', 'ss433', '__ss433', 'ss-433-', 'ss433-', 'SS433_', 'SS433V1', 'SS433 V2'}
                Header.Object = 'SS 433';
                Header.Campaign = 'Micro Quasars';
            case {'Cygnus X-1', 'cygnus x-1', 'Cygnus x-1', 'V1357Cyg', 'CygnusX-1', 'CygnusX1', '__cygx-1', 'CygX1', 'Cyg X1'}
                Header.Object = 'Cygnus X-1';
                Header.Campaign = 'Micro Quasars';
            case {'VVCep', 'VVcep', 'vvcep', 'VV Cep', 'VV cep', 'vv cep', 'vv_cep', '              VV Cep'}
                Header.Object = 'VV Cep';
                Header.Campaign = 'VV Cep Stars';
            case {'31cyg', '31Cyg', '31 cyg', '31 Cyg', '31_cyg', '31_Cyg'}
                Header.Object = '31 Cyg';
                Header.Campaign = 'VV Cep Stars';
            case {'32cyg', '32Cyg', '32 cyg', '32 Cyg', '32_cyg', '32_Cyg'}
                Header.Object = '32 Cyg';
                Header.Campaign = 'VV Cep Stars';
            case {'zet Aur', 'zetAur', 'zet aur', 'zeta Aur', 'zeta aur', 'zet_Aur', 'zet_aur'}
                Header.Object = 'zet Aur';
                Header.Campaign = 'VV Cep Stars';
%            case {'', '', '', '', ''}
%                Header.Object = '';
        end

    % OBS DATE & EXPOSURE TIME data
    case 'DATE-OBS'
        Date = 1;
        if length(kwd {l,2}) == 17
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuuMMdd''T''HH:mm:ss','TimeZone','UTC');
        elseif length(kwd {l,2}) == 18
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuuMMdd''T:''HH:mm:ss','TimeZone','UTC');
        elseif length(kwd {l,2}) == 19
            if strcmp(kwd{l,2}(14),'-')
                Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH-mm:ss','TimeZone','UTC');
            else
                Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss','TimeZone','UTC');
            end
        elseif  length(kwd {l,2}) == 20
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.','TimeZone','UTC');
        elseif  length(kwd {l,2}) == 21
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.S','TimeZone','UTC');
        elseif  length(kwd {l,2}) == 22
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.SS','TimeZone','UTC');
        elseif  length(kwd {l,2}) >= 23
            Header.Date = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.SSS','TimeZone','UTC');
        elseif  isempty(kwd {l,2})
            Header.Date = kwd {l,2};
            Date = 0;
        end
    case 'DATE-END'
        DateEnd = 1;
        if length(kwd {l,2}) == 17
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuuMMdd''T''HH:mm:ss','TimeZone','UTC');
        elseif length(kwd {l,2}) == 18
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuuMMdd''T:''HH:mm:ss','TimeZone','UTC');
        elseif length(kwd {l,2}) == 19
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss','TimeZone','UTC');
        elseif  length(kwd {l,2}) == 20
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.','TimeZone','UTC');
        elseif  length(kwd {l,2}) == 21
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.S','TimeZone','UTC');
        elseif  length(kwd {l,2}) == 22
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.SS','TimeZone','UTC');
        elseif  length(kwd {l,2}) >= 23
            Header.DateEnd = datetime(kwd {l,2},'InputFormat','uuuu-MM-dd''T''HH:mm:ss.SSS','TimeZone','UTC');
        elseif  isempty(kwd {l,2})
            Header.DateEnd = kwd {l,2};
            DateEnd = 0;
        end
    case {'DATE-JD','JD-OBS'}
        Header.JD = kwd {l,2};
        JD = 1;
    case {'MJD-OBS'}
        Header.JD = 2400000 + kwd {l,2};
        JD = 1;
    case 'MID-HJD'
        Header.MidHJD = kwd {l,2};
        MidHJD = 1;
    case {'EXPTIME','EXPOSURE'} % Exposure to light / TBD: check when EXPTIME ~= EXPOSURE !!!
        if isnumeric(kc) % Some FITS file have EXPOSURE numeric and EXPTIME string
            Header.Exposure = kwd {l,2};
            Exposure = 1;
        end
    case 'EXPTIME2' % Total exposure duration (including in-between read-out time)
        Header.ExpTimeTotal = kwd {l,2};
        ExpTimeTotal = 1;
   
    % OBSERVER data
    case 'OBSERVER'
        Header.Observer = kwd {l,2};
        Observer = 1;
        switch Header.Observer
            case 'Paolo Berardi'
                Header.ObserverCode = 'BER';
            case {'cbuil','cbuil   '}
                Header.ObserverCode = 'CBU'; % To be confirmed !!!
            case {'Christian Kreider','ChK     ','ChK'}
                Header.ObserverCode = 'CHK';
            case 'Ch. REVOL'
                Header.ObserverCode = 'CRE';
            case {'D.Boyd  ','D.Boyd'}
                Header.ObserverCode = 'DBO';
                %Header.SiteCode = 'WCO-UK';
            case {'DongLi  ','DongLi'}
                Header.ObserverCode = 'DLI';
            case 'ETB'
                Header.ObserverCode = 'EBE';
            case 'fboubault'
                Header.ObserverCode = 'FBO';
            case {'fteyssier','Francois Teyssier','FTeyssier'}
                Header.ObserverCode = 'FMT';               
            case 'kgraham '
                Header.ObserverCode = 'GKA';
            case {'A. Garcia  J. Guarro','J. Guarro'}
                Header.ObserverCode = 'JGU'; % To be confirmed !!!
            case 'JJ Broussat'
                Header.ObserverCode = 'JJB'; % To be confirmed !!!
            case 'Jacques Montier'
                Header.ObserverCode = 'JMO';
            case {'JEdlin  ','JEdlin'}
                Header.ObserverCode = 'JPE';
            case {'JP MASVIEL','JP Masviel'}
                Header.ObserverCode = 'JPM'; % To be confirmed !!!
            case {'tlester','tlester '}
                Header.ObserverCode = 'LES';
            case 'Malcolm Locke'
                Header.ObserverCode = 'MLO'; % To be confirmed !!!
            case {'Nico Montigiani, Massimiliano Mannucci','Nico Montigiani, Massimiliano Mannucci, Lapo Ferrini'}
                Header.ObserverCode = 'NMO'; % To be confirmed !!!
            case {'Olivier garde','Olivier Garde'}
                Header.ObserverCode = 'OGA';
                % Header.SiteCode = 'OTO-FR';
            case {'Olivier THIZY','Olivier Thizy','Olivier Thizy, Ribeiro J','Olivier Thizy, MASVIEL','Olivier THIZY, Christian BUIL, Valerie DESNOUX, Michel PUJOL','Olivier Thizy, A Lopez, P Dubreuil, G Kobber'}
                Header.ObserverCode = 'OTH';
            case 'Pollmann'
                Header.ObserverCode = 'POL';
                % Header.SiteCode = 'LEV-DE';
            case {'Pierre DUBREUIL','Pierre Dubreuil'}
                Header.ObserverCode = 'PDU'; % To be confirmed !!!
            case {'PSO','psomogyi'}
                Header.ObserverCode = 'PSO';
            case 'Leadbeater'
                Header.ObserverCode = 'RLE'; % To be confirmed !!!
            case 'S. Charbonnel'
                Header.ObserverCode = 'SCH'; % To be confirmed !!!
            case 'TBohlsen'
                Header.ObserverCode = 'TBO'; % To be confirmed !!!
            case 'Umberto Sollecchia'
                Header.ObserverCode = 'USO'; % To be confirmed !!!
            case ''
                Header.ObserverCode = ''; % To be confirmed !!!
            case ''
                Header.ObserverCode = ''; % To be confirmed !!!
            case ''
                Header.ObserverCode = ''; % To be confirmed !!!
            case ''
                Header.ObserverCode = ''; % To be confirmed !!!
            otherwise
                Header.ObserverCode = '---';
        end
   
    % SITE LOCATION data
    case {'BSS_SITE','ORIGIN','SITENAME'}
        Header.SiteObs = kwd {l,2};
        Site = 1;
        switch Header.SiteObs
            case {'Saint-Veran','AQ-St Veran'}
                Header.SiteCode = 'AAQ-FR'; % To be confirmed !!!
            case 'C.A.L.C'
                Header.SiteCode = 'ALC-FR'; % To be confirmed !!!
            case {'AMPERE LYON(FR)','AMPERE(Lyon)'}
                Header.SiteCode = 'AMP-FR'; % To be confirmed !!!
            case 'Lac Appolinaire'
                Header.SiteCode = 'APP-FR'; % To be confirmed !!!
            case 'LAquila'
                Header.SiteCode = 'AQL-IT'; % To be confirmed !!!
            case 'Arnprior_ON_CA'
                Header.SiteCode = 'ARN-CA'; % To be confirmed !!!
            case 'Aspremont (06)'
                Header.SiteCode = 'ASP-FR'; % To be confirmed !!!
            case 'Bellavista Obs. L'
                Header.SiteCode = 'BEL-IT'; % To be confirmed !!!
            case 'Observatoire du CALA'
                Header.SiteCode = 'CAL-FR'; % To be confirmed !!!
            case 'Castanet'
                Header.SiteCode = 'CAS-FR'; % To be confirmed !!!
            case 'Christchurch-NZ'
                Header.SiteCode = 'CHR-NZ'; % To be confirmed !!!
            case 'Jade Tianjin'
                Header.SiteCode = 'JAD-CN';
            case 'Obs Pollmann Leverkusen'
                Header.SiteCode = 'LEV-DE';
            case 'Mill Ridge_ON_CA'
                Header.SiteCode = 'MIR-CA'; % To be confirmed !!!
            case 'Mirranook Armidale'
                Header.SiteCode = 'MIR-AU'; % To be confirmed !!!
            case 'Molines'
                Header.SiteCode = 'MOL-FR'; % To be confirmed !!!
            case 'Observatoire Astronomique d''Osenbach'
                Header.SiteCode = 'OAO-FR'; % To be confirmed !!!
            case {'OAF-FR','OAF'}
                Header.SiteCode = 'OAF-FR';
            case {'38420 Revel','Observatoire Belle Etoile'}
                Header.SiteCode = 'OBE-FR';
            case {'Observatoire de la Tourbière','Observatoire de la Tourbiere'}
                Header.SiteCode = 'OTO-FR';
            case {'OHP     ','OHP','Haute Provence','Haute Provence'}
                Header.SiteCode = 'OHP-FR';
            case 'Pic du Midi'
                Header.SiteCode = 'PIC-FR'; % To be confirmed !!!
            case {'Rouen','Rouen   '}
                Header.SiteCode = 'ROU-FR';
            case 'Saint-Jean Illac'
                Header.SiteCode = 'SJI-FR'; % To be confirmed !!!
            case {'STA. MARIA DE MONTMAGASTRELL','Sta. Maria M.','Sta. Maria de Montmagastrell'}
                Header.SiteCode = 'SMM-ES'; % To be confirmed !!!
            case 'San Polo a Mosciano AAF'
                Header.SiteCode = 'SPM-??'; % To be confirmed !!!
            case {'TAT-HU','Tata'}
                Header.SiteCode = 'TAT-HU';
            case 'Three Hills Observatory'
                Header.SiteCode = 'THO-UK'; % To be confirmed !!!
            case {'OTSP2014','Okie-Tex Star Party 2015'}
                Header.SiteCode = 'TSP-US'; % To be confirmed !!!
            case 'West Challow UK'
                Header.SiteCode = 'WCO-UK';
            case 'St Sordelin'
                Header.SiteCode = 'SOR-FR'; % To be confirmed !!!
            case ''
                Header.SiteCode = ''; % To be confirmed !!!
            case ''
                Header.SiteCode = ''; % To be confirmed !!!
            case ''
                Header.SiteCode = ''; % To be confirmed !!!
            case ''
                Header.SiteCode = ''; % To be confirmed !!!
            case ''
                Header.SiteCode = ''; % To be confirmed !!!
            otherwise
                Header.SiteCode = '-------';
        end

    % EQUIPMENT data
    case {'BSS_INST','INSTRUME'}
        Header.Instrument = kwd {l,2};
        Instrument = 1;
    case {'BSS_ITRP','SPE_RPOW'}
        Header.Resolution = kwd {l,2};
        Resolution = 1;
    end

end

% Manage missing data/keyword in the header
Header.Valid = 1; % Means data is valid

if Exposure == 0 % Without exposure time, we considere the spectrum not valid (TBD: manage other fields ~= '[]' but Exposure == 0)
    Header.Exposure = 0;
    Header.Valid = 0;
end

if WaveOrigin == 0
    Header.WaveOrigin = 0;
end
if Dispersion == 0
    Header.Dispersion = 0;
    Header.WaveMax = 0;
else
    if NAXIS1 == 0
        Header.WaveMax = 0;
    else   
        Header.WaveMax = Header.WaveOrigin + Header.NAXIS1 * Header.Dispersion;
    end
end


if (Object == 0) || (strcmp(Header.Object,''))
    Header.Object = '???';
    Header.Valid = 0; % Without object name, data is invalid (to be confirmed)
end

% Date & Exposure/Duration Time
if Date == 0
    Header.Date = 0;
    Valid = 0; % Without date, data is invalid (to be confirmed)
end

if Header.Valid == 1
    if DateEnd == 0
        if Date == 0
            Header.DateEnd = 0;
        else
            if Exposure == 0
                Header.DateEnd = 0;
            else
                Header.DateEnd = Header.Date + seconds(Header.Exposure);
            end
        end
    end
end

%if ExpTimeTotal == 0
    if Header.Valid == 0
        Header.ExpTimeTotal = 0;
    else
        Header.ExpTimeTotal = seconds(Header.DateEnd - Header.Date);
    end
%end

% Calculated mid JD - TEMPORARY
if (Date == 0) || (Header.Valid == 0)
    Header.CalcJD = 0;
else
    Header.CalcJD = juliandate(Header.Date + seconds(Header.ExpTimeTotal / 2));
end

if JD == 0
    Header.JD = 0;
end

if MidHJD == 0
    Header.MidHJD = 0;
end

% Other fields...
if Observer == 0
    Header.Observer = '???';
    Header.ObserverCode = '???';   
end

if Site == 0
    if strcmp(Header.ObserverCode,'OTH')
        Header.Site = 'Observatoire Belle Etoile';
        Header.SiteCode = 'OBE-FR';
    else
        Header.Site = '???';
        Header.SiteCode = '??????';
    end
end

if Instrument == 0
    Header.Instrument = '????';
end
if strcmp(Header.Instrument,'eshel_6H-101')
    Header.Observer = 'OTH-FR';
end

if Header.Dispersion == 0
    Header.Dispersion = double((Header.WaveMax - Header.WaveOrigin))/double(Header.NAXIS1);
end
if Resolution == 0 % Resolution is actually the Power of Resolution (R)
    % If power of resolution is not provided, assume dispersion is resolution/2.5
    % (Nyquist criteria)
    Header.Resolution = ((Header.WaveMax - Header.WaveOrigin)/2)/(2.5*double(Header.Dispersion));
end

for a = 1 : Header.NAXIS1
    Header.Wavelength (a) = Header.WaveOrigin + (a-1) * Header.Dispersion;
     Header.Intensity (a) = Data (1,a);
end

return