\chapter{Task Programming Manual}

\textbf{\large CAUTION: This section has NOT yet been
FULLY updated for the Gildas Data Format Version 2 (GDFV2).
Please refer to the \emph{sic-gdfv2} document.\\
More information is given in each section.}


\section{General Outline and Data Structure of Images}

\textbf{Section basically up to date}

The \gildas\ software is designed to work in an heterogeneous network,
where each computer may have its own floating point and integer number
representation and its own operating system. Images created on any computer
should be accessible transparently from any other computer in the network.

To allow such a portability and yet preserve efficiency when working on a
single type of machines, all files are written in the binary representation
of the machine on which they were created. A library of subroutines is used
to access the images and perform the necessary format conversion between
the different representations of real and integer numbers. So far, 3
representations are recognized: VAX format (a dead dinosaur...), 
IEEE format (the so-called
big-endians, like DEC DS Workstation, Intel \& AMD PCs and most affordable
current computers) 
and EEEI format (big-endians, like Sun SparcStation, IBM RS-6000 series, and
other obsolescent machines...).

The images have the following organization :
\begin{itemize}
\item Images are basically direct access files with a logical blocksize of 512
  bytes. This correspond to the system block size on VAX-VMS machines.
\item The first block is a header block, defining the size of the image and
  all major parameters, such as World Coordinate System definition.
\item The following blocks containing the image array itself.
\item There may be trailing blocks for additional information. These
  trailing blocks are not compulsory, and may be ignored by the processing
  software.
\item the number of logical blocks is rounded upwards to a multiple of 16 blocks,
to allow reading with 8192 byte blocks.
\end{itemize}

The header starts with 'GILDAS', followed by one character which indicates
the type of integer and floating point number representation\\
\begin{itemize}
\item The inferior sign ``{\tt  $>$}'' for swapped IEEE machines (big-endians, IBM RS-6000, SUN Sparc, etc...),
with a 64-bit header (so-called GDFV2 data version)
\item The superior sign ``{\tt  $<$}'' for non-swapped IEEE machines (little-endians)
with a 64-bit header (so-called GDFV2 data version)
\item Underscore ``{\tt \_}'' for VAX machines
\item Dot ``.'' for swapped IEEE machines (IBM RS-6000, SUN Sparc, etc...)
\item Minus ``{\tt -}'' for non-swapped IEEE machines (DEC DS series)
\end{itemize}
The last 3 cases are inherited from the GDFV1 data version, in which all size informations
were limited to 32-bit numbers. The latest GDFV2 data version has some integers using
64 bit values to handle large data sets.

After the version/hardware sign, an extra text indicates the type of information in the image:
\begin{itemize}
\item {\tt IMAGE} for all images (up to 4-D arrays)
\item {\tt UVFIL} for UV tables
\end{itemize}
This character string, being human readable, is intended for quick checks, but 
a more specific information
about the actual type of data file is available through an integer code in the
data header.

\section{Fortran-90 access to images}


\textbf{Section basically up to date}

Fortran-90 allows definition of data structures (derived types) which are
convenient to handle data structures. Data access to GILDAS files is 
done by reading all or part of the data into memory, 
using standard FORTRAN direct I/O. The header is read into a specific
Fortran derived type, the \texttt{gildas} derived part, which has
a sub-type mimicking the file header plus ancillary information
re-organized for convenience. The data can be
read into standard Fortran arrays. Fortran pointers are provided as
placeholders for this purpose in the \texttt{gildas} data type for 
rank 1 to 4 real arrays. 

The portable version of the \gildas\ software makes the distinction between
an image and the "incarnation" of an image subset in memory.  Each image
has an associated "Image Slot" (IS), while each memory part has an
associated "Memory Slot" (MS). Several memory slots may corresponds to
several "windows" into a single image slot.

The Fortran-90 module \texttt{image\_def}
defines the \texttt{gildas} derived type.

\begin{verbatim}
!
module image_def
  use gildas_def
  use gbl_format
  use gio_headers
  !
  !
  type :: gildas
    sequence
    character(len=256)   :: file = ' '  ! File name
    type (strings)       :: char        !
    type (location)      :: loca        !
    type (gildas_header_v2) :: gil      !
    integer(kind=index_length) :: blc(gdf_maxdims) = 0       ! Bottom left corner
    integer(kind=index_length) :: trc(gdf_maxdims) = 0       ! Top right corner
    integer(kind=4) :: header = 0       ! Defined / Undefined
    integer(kind=4) :: status = 0       ! Last error code
    real,         pointer :: r1d(:)       => null()  ! Pointer to 1D data
    real(kind=8), pointer :: d1d(:)       => null()
    integer,      pointer :: i1d(:)       => null()
    real,         pointer :: r2d(:,:)     => null()  ! Pointer to 2D data
    real(kind=8), pointer :: d2d(:,:)     => null()
    integer,      pointer :: i2d(:,:)     => null()
    real,         pointer :: r3d(:,:,:)   => null()  ! Pointer to 3D data
    real(kind=8), pointer :: d3d(:,:,:)   => null()
    integer,      pointer :: i3d(:,:,:)   => null()
    real,         pointer :: r4d(:,:,:,:) => null()  ! Pointer to 4D data
    real(kind=8), pointer :: d4d(:,:,:,:) => null()
    integer,      pointer :: i4d(:,:,:,:) => null()
  end type gildas
  !
end module image_def
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
\end{verbatim}

The type \texttt{gildas\_v2} closely mimicks the actual layout
of the data file, but is \textbf{** not **} identical. Some of its
content are provided as convenience to handle the quantities, but are
\textbf{** not **} intended to be used directly in the application programs.
The \texttt{ijxyz((3)} (where \texttt{xyz} can be \texttt{typ, lin, sou, 
sys, uni, cod}) pseudo-integer arrays in particular should never
be used and may disappear in future releases (or become private). 
They correspond to the character strings held in the derived type \texttt{strings}.

\begin{verbatim}
  type :: gildas_header_v2
     !
     ! Spread on two blocks
     !
     ! Block 1: Basic Header and Dimension information
     sequence
     !
     ! Trailer:
     integer(kind=4) :: ijtyp(3) = 0       !  1  Image Type
     integer(kind=4) :: form    = fmt_r4   !  4  Data format (FMT_xx)
     integer(kind=8) :: ndb     = 0        !  5  Number of blocks
     integer(kind=4) :: nhb     = 2        !  7  Number of header blocks
     integer(kind=4) :: ntb     = 0        !  8  Number of trailing blocks
     integer(kind=4) :: version_gdf = code_version_gdf_current !  9  Data format Version number
     integer(kind=4) :: type_gdf =  code_gdf_image  !  10 code_gdf_image or code_null
     integer(kind=4) :: dim_start = gdf_startdim    !  11  Start offset for DIMENSION, should be odd, >12
     integer(kind=4) :: pad_trail
     ! The maximum value would be 17 to hold up to 8 dimensions.
     !
     ! DIMENSION Section. Caution about alignment...
     integer(kind=4) :: dim_words   = 2*gdf_maxdims+2  ! at s_dim=17  Dimension section length
     integer(kind=4) :: blan_start !! = dim_start + dim_lenth + 2   ! 18  Pointer to next section
     integer(kind=4) :: mdim    = 4        !or > ! 19  Maximum number of dimensions in this data format
     integer(kind=4) :: ndim    = 0        ! 20  Number of dimensions
     integer(kind=index_length) :: dim(gdf_maxdims) = 0     ! 21  Dimensions
     !
     ! BLANKING
     integer(kind=4) :: blan_words = 2     ! Blanking section length
     integer(kind=4) :: extr_start         ! Pointer to next section
     real(kind=4) :: bval = +1.23456e+38   ! Blanking value
     real(kind=4) :: eval = -1.0           ! Tolerance
     !
     ! EXTREMA
     integer(kind=4) :: extr_words = 6    ! Extrema section length
     integer(kind=4) :: coor_start !! = extr_start + extr_words +2     !
     real(kind=4) :: rmin    = 0.0         ! Minimum
     real(kind=4) :: rmax    = 0.0         ! Maximum
     integer(kind=index_length) :: minloc(gdf_maxdims) = 0 ! Pixel of minimum
     integer(kind=index_length) :: maxloc(gdf_maxdims) = 0 ! Pixel of maximum
! in file:     integer(kind=8) :: mini = 0           ! Rank 1 pixel of minimum
! in file:     integer(kind=8) :: maxi = 0           ! Rank 1 pixel of maximum
     !
     ! COORDINATE Section
     integer(kind=4) :: coor_words  = 6*gdf_maxdims   ! at s_coor  Section length
     integer(kind=4) :: desc_start  !! = coord_start + coord_words +2     !
     real(kind=8)    :: convert(3,gdf_maxdims)   !  Ref, Val, Inc for each dimension
     !
     ! DESCRIPTION Section
     integer(kind=4) :: desc_words  = 3*(gdf_maxdims+1) ! at s_desc, Description section length
     integer(kind=4) :: null_start  !! = desc_start + desc_words +2     !
     integer(kind=4) :: ijuni(3)   = 0        ! Data Unit
     integer(kind=4) :: ijcod(3,gdf_maxdims) = 0    ! Axis names
     integer(kind=4) :: pad_desc              ! For Odd gdf_maxdims only
     !
     !
     ! The first block length is thus
     !	s_dim-1 + (2*mdim+4) + (4) + (8) +  (6*mdim+2) + (3*mdim+5)
     ! = s_dim-1 + mdim*(2+6+3) + (4+4+2+5+8)
     ! = s_dim-1 + 11*mdim + 23
     ! With mdim = 7, s_dim=11, this is 110 spaces
     ! With mdim = 8, s_dim=11, this is 121 spaces
     ! MDIM > 8 would NOT fit in one block...
     !
     ! Block 2: Ancillary information
     !
     ! The same logic of Length + Pointer is used there too, although the
     ! length are fixed. Note rounding to even number for the pointer offsets
     ! in order to preserve alignement...
     !
     integer(kind=4) :: posi_start  = 1
     !
     ! POSITION
     integer(kind=4) :: posi_words = 15    ! Position section length: 15 used + 1 padding
     integer(kind=4) :: proj_start         !! = s_posi + 16     ! Pointer to next section
     integer(kind=4) :: ijsou(3) = 0       ! 75  Source name
     integer(kind=4) :: ijsys(3) = 0       ! 71  Coordinate System (moved from Description section)
     real(kind=8) :: ra         = 0.d0     ! 78  Right Ascension
     real(kind=8) :: dec        = 0.d0     ! 80  Declination
     real(kind=8) :: lii        = 0.d0     ! 82  Galactic longitude
     real(kind=8) :: bii        = 0.d0     ! 84           latitude
     real(kind=4) :: epoc       = 0.0      ! 86  Epoch of coordinates
     real(kind=4) :: pad_posi
     !
     ! PROJECTION
     integer(kind=4) :: proj_words = 9     ! Projection length: 9 used + 1 padding
     integer(kind=4) :: spec_start !! = proj_start + 12
     real(kind=8) :: a0      = 0.d0        ! 89  X of projection center
     real(kind=8) :: d0      = 0.d0        ! 91  Y of projection center
     real(kind=8) :: pang    = 0.d0        ! 93  Projection angle
     integer(kind=4) :: ptyp = p_none      ! 88  Projection type (see p_... codes)
     integer(kind=4) :: xaxi = 0           ! 95  X axis
     integer(kind=4) :: yaxi = 0           ! 96  Y axis
     integer(kind=4) :: pad_proj
     !
     ! SPECTROSCOPY
     integer(kind=4) :: spec_words  = 14   ! Spectroscopy length: 14 used
     integer(kind=4) :: reso_start  !! = spec_words + 16
     real(kind=8) :: fres       = 0.d0     !101  Frequency resolution
     real(kind=8) :: fima       = 0.d0     !103  Image frequency
     real(kind=8) :: freq       = 0.d0     !105  Rest Frequency
     real(kind=4) :: vres       = 0.0      !107  Velocity resolution
     real(kind=4) :: voff       = 0.0      !108  Velocity offset
     real(kind=4) :: dopp       = 0.0      !     Doppler factor
     integer(kind=4) :: faxi    = 0        !109  Frequency axis
     integer(kind=4) :: ijlin(3) = 0       ! 98  Line name
     integer(kind=4) :: vtyp    = vel_unk  ! Velocity type (see vel_... codes)
     !
     ! RESOLUTION
     integer(kind=4) :: reso_words = 3     ! Resolution length: 3 used + 1 padding
     integer(kind=4) :: nois_start !! = reso_words + 6
     real(kind=4) :: majo    = 0.0         !111  Major axis
     real(kind=4) :: mino    = 0.0         !112  Minor axis
     real(kind=4) :: posa    = 0.0         !113  Position angle
     real(kind=4) :: pad_reso
     !
     ! NOISE
     integer(kind=4) :: nois_words = 2     ! Noise section length: 2 used
     integer(kind=4) :: astr_start !! = s_nois + 4
     real(kind=4) :: noise   = 0.0         ! 115 Theoretical noise
     real(kind=4) :: rms     = 0.0         ! 116 Actual noise
     !
     ! ASTROMETRY
     integer(kind=4) :: astr_words = 3    ! Proper motion section length: 3 used + 1 padding
     integer(kind=4) :: uvda_start !! = s_astr + 4
     real(kind=4) :: mura     = 0.0        ! 118 along RA, in mas/yr
     real(kind=4) :: mudec    = 0.0        ! 119 along Dec, in mas/yr
     real(kind=4) :: parallax = 0.0        ! 120 in mas
     real(kind=4) :: pad_astr
     ! real(kind=4) :: pepoch   = 2000.0     ! 121 in yrs ?
     !
     ! UV_DATA information
     integer(kind=4) :: uvda_words  = 18+2*code_uvt_last ! Length of section: 14 used
     integer(kind=4) :: void_start  !! = s_uvda + l_uvda + 2
     integer(kind=4) :: version_uv = code_version_uvt_current  ! 1 version number. Will allow us to change the data format
     integer(kind=4) :: nchan = 0         ! 2 Number of channels
     integer(kind=8) :: nvisi = 0         ! 3-4 Independent of the transposition status
     integer(kind=4) :: nstokes = 0       ! 5 Number of polarizations
     integer(kind=4) :: natom = 0         ! 6. 3 for real, imaginary, weight. 1 for real.
     real(kind=4)    :: basemin = 0.      ! 7 Minimum Baseline
     real(kind=4)    :: basemax = 0.      ! 8 Maximum Baseline
     integer(kind=4) :: fcol              ! 9 Column of first channel
     integer(kind=4) :: lcol              ! 10 Column of last  channel
     ! The number of information per channel can be obtained by
     !       (lcol-fcol+1)/(nchan*natom)
     ! so this could allow to derive the number of Stokes parameters
     ! Leading data at start of each visibility contains specific information
     integer(kind=4) :: nlead = 7           ! 11 Number of leading informations (at lest 7)
     ! Trailing data at end of each visibility may hold additional information
     integer(kind=4) :: ntrail = 0          ! 12 Number of trailing informations
     !
     ! Leading / Trailing information codes have been specified before
     integer(kind=4) :: column_pointer(code_uvt_last) = code_null ! Back pointer to the columns...
     integer(kind=4) :: column_size(code_uvt_last) = 0  ! Number of columns for each
     ! In the data, we instead have the codes for each column
     ! integer(kind=4) :: column_codes(nlead+ntrail)         ! Start column for each ...
     ! integer(kind=4) :: column_types(nlead+ntrail) /0,1,2/ ! Number of columns for each: 1 real*4, 2 real*8
     ! Leading / Trailing information codes
     !
     integer(kind=4) :: order = 0          ! 13  Stoke/Channel ordering
     integer(kind=4) :: nfreq = 0          ! 14  ! 0 or = nchan*nstokes
     integer(kind=4) :: atoms(4)           ! 15-18 Atom description
     !
     real(kind=8), pointer :: freqs(:) => null()     ! (nchan*nstokes) = 0d0
     integer(kind=4), pointer :: stokes(:) => null() ! (nchan*nstokes) or (nstokes) = code_stoke
     !
     ! back pointers to the ref,val,inc naming convention
     real(kind=8), pointer :: ref(:) => null()
     real(kind=8), pointer :: val(:) => null()
     real(kind=8), pointer :: inc(:) => null()
  end type gildas_header_v2 
\end{verbatim}

Access to images is very simple. It requires only 3 steps: \textit{i)} to
read the header from an existing file, or to create a new header,
\textit{ii)} to allocate the data, \textit{iii)} to read or write the data.
An example is given below.

\begin{verbatim}
program image_example
  use image_def                                       ! 1
  use gkernel_interfaces
  logical error
  integer ier
  character*32 name1,name2
  !
  type (gildas) :: input_image, output_image          ! 2
  real, allocatable :: dinput(:,:), doutput(:,:,:)    ! 3
  !
  call gildas_open
  call gildas_char('INPUT$',name1)
  call gildas_char('OUTPUT$',name2)
  call gildas_close
  !
  call gildas_null(input_image, type='IMAGE')         ! 4
  call sic_parsef (name1,input_image%file,' ','.gdf') ! 5
  call gdf_read_header (input_image,error)            ! 6
  if (error) then
    call gagout('E-IMAGE_EXAMPLE, Error opening input file')
    call sysexi(fatale)
  endif
  allocate(dinput(input_image%gil%dim(1),input_image%gil%dim(2), &
        stat=ier)                                     ! 7
  if (ier.ne.0) then
    call gagout('e-image_example, error allocating memory')
    call sysexi(fatale)
  endif
  call gdf_read_data (input_image, dinput, error)     ! 8
  if (error) then
    call gagout('E-IMAGE_EXAMPLE, error reading input file')
    call sysexi(fatale)
  endif
  !
  ! Create an output image
  !-----------------------
  call gdf_copy_header (input_image, output_image)    ! 9
  call sic_parsef (name2,output_image%file,' ','.gdf')! 10
  output_image%gil%ndim = 3                           ! 11
  output_image%gil%dim(1) = input_image%gil%dim(1)    ! 11
  output_image%gil%dim(2) = input_image%gil%dim(2)    ! 11
  output_image%gil%dim(3) = 4                         ! 11
  allocate(doutput(output_image%gil%dim(1), &
    output_image%gil%dim(2),output_image%gil%dim(3), &
    stat=ier)                                         ! 12
  if (ier.ne.0) then
    call gagout('E-IMAGE_EXAMPLE, Error allocating memory')
    call sysexi(fatale)
  endif
  !
  ! Do something with the data
  doutput(:,:,3) = dinput
  !
  ! Write the output image
  call gdf_write_image(output_image,doutput,error)    ! 13
  if (error) then
    call gagout('E-IMAGE_EXAMPLE, Error writing output file')
    call sysexi(fatale)
  endif
  !
  deallocate(dinput,doutput)
  end
\end{verbatim}
\begin{enumerate}
\item USE the module containing the GILDAS derived type definitions
\item Define the input and output image headers
\item Define the input and output data as allocatable arrays
\item Initialize the input image header. Argument \texttt{type} 
is optional, and default to \texttt{``IMAGE''}
\item Prepare the input file name, \texttt{INPUT\_IMAGE\%FILE}
\item Read the header to initialize the \texttt{INPUT\_IMAGE} structure.
\item Allocate the data. Note that it is assumed here to be a 2-D array.
\item Read the data, using the information provided in the header structure
  (in particular the file name).
\item Define the output header, here by making a copy of the input header
\item Setup the output file name
\item Change the output header parameters as needed
\item Allocate the output image data
\item Create and write the output image
\end{enumerate}

The subroutines using GILDAS headers are:
\begin{itemize}
\item\texttt{SUBROUTINE GILDAS\_NULL(HEADER)} \\
  Initialize a header. \textbf{No access to header components should
  be done before this, as some variables are dangling pointers before
  initialization.}
\item\texttt{SUBROUTINE GDF\_COMPARE\_SHAPE(FIRST,SECOND,EQUAL)} \\
  Compare the shape of the two images defined by the two headers
\item\texttt{SUBROUTINE GDF\_READ\_HEADER(IMAG,ERROR)} \\
  Read the image header. \texttt{IMAG\%FILE} must have been initialized
  before.
\item\texttt{SUBROUTINE GDF\_UPDATE\_HEADER(IMAG,ERROR)} \\
  Update an image header: write the modified header to the image file.
\item\texttt{SUBROUTINE GDF\_COPY\_HEADER(INPUT,OUTPUT)} \\
  Copy an input header structure to an output header structure
\item\texttt{SUBROUTINE GDF\_TRANSPOSE\_HEADER(INPUT,OUTPUT,ORDER,ERROR)}\\
  Transpose a header according to given transposition code. This routine
  transposes the axes information, but not the data.
\end{itemize}

\section{GIO API}

\textbf{Missing section, see the \emph{sic-gdfv2} document.}

\section{Obsolete Fortran-77 access routines}

\textbf{Caution: These routines are obsolete. Documentation
only provided for historical reasons. It may disappear at some
point or be moved to another document.\\}
In Fortran-77, neither virtual memory handling, nor data structures, are
part of the language.  We had written a number of routines to access
images.  These routines are more complex than the new Fortran-90 method of
access, and are provided here just for completeness.

To read a file requires six basic steps:
\begin{itemize}
\item allocation of an {\em Image Slot} using {\tt GDF\_GEIS}.
\item connection of an image to the slot using {\tt GDF\_REIS} or {\tt
    GDF\_WRIS}.
\item reading the header using {\tt GDF\_RHSEC}
\item connection of a {\em Memory Slot} to the image (or a subset of it)
  using {\tt GDF\_GEMS}
\item once the {\em Memory Slot} is no longer needed, disconnection using
  {\tt GDF\_FRMS}
\item once the image slot is no longer required, disconnection using {\tt
    GDF\_FRIS}
\end{itemize}

Creation of a new file is slightly different:
\begin{itemize}
\item allocation of an {\em Image Slot} using {\tt GDF\_GEIS}
\item preparatin of the header using e.g. {\tt GDF\_WHSEC}
\item creation of the image to the slot using {\tt GDF\_CRIS}.  The header
  is written at this stage.
\item connection to the image (or a subset of it) using {\tt GDF\_GEMS}
\item once the {\em Memory Slot} is no longer needed, disconnection using
  {\tt GDF\_FRMS}. This is the step which actually does the writing.
\item once the image slot is no longer required, disconnection using {\tt
    GDF\_FRIS}
\end{itemize}

\subsection{Image Slot Handling}

\begin{description}
  \index{GDF\_GEIS}
\item{\tt SUBROUTINE GDF\_GEIS (IS,ERROR)}
\begin{verbatim}
   GDF  GEt Image Slot
        IS      I       Slot number                     Output
        ERROR   L       Error flag                      Output
\end{verbatim}
  {\tt GDF\_GEIS} returns a unique image slot number IS, for further use in
  all other {\tt GDF\_xxxx} routines.  \index{GDF\_CLIS}
\item {\tt SUBROUTINE GDF\_CLIS (IS,ERROR)}
\begin{verbatim}
   GDF  CLose Image Slot
        IS      I       Slot number                     Input
        ERROR   L       Error flag                      Output
\end{verbatim}
  {\tt GDF\_CLIS} close an image slot IS, disconnecting all associated
  memory slot after flushing all pending updates on the image. The image
  slot IS stays reserved, but available for further use.  \index{GDF\_FRIS}
\item{\tt SUBROUTINE GDF\_FRIS (IS,ERROR)}
\begin{verbatim}
   GDF  FRee Image Slot
        IS      I       Slot number                     Input
        ERROR   L       Error flag                      Output
\end{verbatim}
  {\tt GDF\_CLIS} free an image slot IS, disconnecting all associated
  memory slot after flushing all pending updates on the image. The image
  slot IS should no longer be referenced in any call after this operation.
  \index{GDF\_STIS}
\item{\tt INTEGER FUNCTION GDF\_STIS(IS)}
\begin{verbatim}
   GDF  STatus of Image Slot
        IS      I       Slot number                     Input
\end{verbatim}
  Return status of slot: -1 No such slot, 0 Empty (Not allocated), 1 Read
  (Opened for ReadOnly), 2 Full (Allocated but not opened), 3 Write (Opened
  for ReadWrite).
\end{description}

\subsection{Image Connection}

Once a slot is reserved, it must be associated with an image.  The
following 4 routines connect an image to a specified image slot IS, in one
of the 4 possible access modes (CReate, EXtend, REad only, Write and Read).
No part of the image is immediately accessible after that, but the image
slot is ready for memory connection using {\tt GDF\_GEMS}.

\begin{description}
  \index{GDF\_CRIS}
\item{\tt SUBROUTINE GDF\_CRIS (IS,GTYPE,NAME,FORM,SIZE,ERROR)}
\begin{verbatim}
   GDF  CReate Image Slot
   Arguments:
        IS      I       Slot number                     Input
        GTYPE   C*(*)   Image type                      Input
        NAME    C*(*)   File name                       Input
        FORM    I       Image format (Real,Integer...)  Input
        SIZE    I       Image size                      Input
        ERROR   L       Error flag                      Output
\end{verbatim}
  Creates a new file from the information available in image slot {\tt IS}.
  The internal header should have been defined (through calls to {\tt
    GDF\_WHSEC}) before, and is written on the new file header.

  \index{GDF\_EXIS}
\item{\tt SUBROUTINE GDF\_EXIS (IS,GTYPE,NAME,FORM,SIZE,ERROR)}
\begin{verbatim}
   GDF  EXtend Image Slot
   Arguments:
        IS      I       Slot number                     Input
        GTYPE   C*(*)   Image type                      Input
        NAME    C*(*)   File name                       Input
        FORM    I       Image format (Real,Integer...)  Input
        SIZE    I       Image size                      Input
        ERROR   L       Error flag                      Output
\end{verbatim}
  This routine is used to change the size of an image, usually by
  increasing the last dimension of the image. The new internal header must
  have been defined before in image slot {\tt IS}, by use of the {\tt
    GDF\_WHSEC} routine.

  \index{GDF\_REIS}
\item{\tt SUBROUTINE GDF\_REIS (IS,GTYPE,NAME,FORM,SIZE,ERROR)}
\begin{verbatim}
   GDF  REad Image Slot
   Arguments:
        IS      I       Slot number                     Input
        GTYPE   C*(*)   Image type                      Output
        NAME    C*(*)   File name                       Input
        FORM    I       Image format (Real,Integer...)  Output
        SIZE    I       Image size                      Output
        ERROR   L       Error flag                      Output
\end{verbatim}
  This routine is used to open an existing image for ReadOnly operations.
  The image is available for file sharing.  \index{GDF\_WRIS}
\item{\tt SUBROUTINE GDF\_WRIS (IS,GTYPE,NAME,FORM,SIZE,ERROR)}
\begin{verbatim}
   GDF  WRite Image Slot
   Arguments:
        IS      I       Slot number                     Input
        GTYPE   C*(*)   Image type                      Output
        NAME    C*(*)   File name                       Input
        FORM    I       Image format (Real,Integer...)  Output
        SIZE    I       Image size                      Output
        ERROR   L       Error flag                      Output
\end{verbatim}
  This routine is used to open an existing image for ReadWrite operations.
  The image is not available for file sharing.
\end{description}

\subsection{Memory Connection}

After an image is connected, a part of it should be brought into virtual
memory. The access type for this virtual memory area (ReadOnly or
ReadWrite) depends on the type of image connection.  \index{GDF\_GEMS}
\begin{verbatim}
        SUBROUTINE GDF_GEMS (MS, IS, BLC, TRC, ADDR, FORM, ERROR)
  ----------------------------------------------------------------------
   GDF  Get Memory Slot
        MS      I       Memory Slot number              Output
        IS      I       Image Slot number               Input
        BLC     I(4)    Bottom Left Corner              Input
        TRC     I(4)    Top Right Corner                Input
        ADDR    I       Virtual memory address          Output
        FORM    I       Type of data                    Input
        ERROR   L       Logical error flag              Output
  ----------------------------------------------------------------------
\end{verbatim}
{\tt GDF\_GEMS} reads a subset of the image connected to slot IS into a
memory area (memory slot MS) located at address ADDR.  The image subset is
"incarnated" into the specified data type FORM, which may be different from
the image data type. When BLC(i) and TRC(i) are set to zero, they default
to the current image dimension (i.e BLC(i)=1 and TRC(i)=Dim(i)). After this
routine, virtual memory address ADDR is the start of an array of type FORM
containing an incarnation of the image subset that can be used for further
processing.  \index{GDF\_FRMS}
\begin{verbatim}
        SUBROUTINE GDF_FRMS (MS,ERROR)
  ----------------------------------------------------------------------
   GDF  FRee Memory Slot
  ----------------------------------------------------------------------
\end{verbatim}
{\tt GDF\_FRMS} Frees the memory slot MS. If the connected image was
connected with write access, the image is updated. The memory slot is no
longer available after this operation.  \index{GDF\_UPMS}
\begin{verbatim}
        SUBROUTINE GDF_UPMS (MS,ERROR)
  ----------------------------------------------------------------------
   GDF  UPdate Memory Slot
  ----------------------------------------------------------------------
\end{verbatim}
{\tt GDF\_UPMS} Updates the image connected to the memory slot MS.  The
memory slot is left unmodified. This routine is provided for safety
measures.

The I/O (or mapping) are thus only done in the {\tt GDF\_something} routines, in
a system dependent way. All data format translation (incarnation in a
different type, or machine dependent data types) are done at this level.
This allows a transparent operation in an heterogeneous environment.


\section{Creating GILDAS Tasks}
GILDAS tasks (e.g. for task ``{\tt taskname}'') are composed of 4 different
parts :
\begin{itemize}
\item The program, {\tt taskname.exe}.
\item A help text file, {\tt taskname.hlp}
\item The initialization file, {\tt taskname.init}, read by commands {\tt
    RUN} and {\tt SUBMIT} to get from the user the task input parameters.
\item Optionally, a checker file, {\tt taskname.check}, read by commands
{\tt RUN}  and {\tt SUBMIT}, to check the input parameters and pass them to the
  task. It is optional: \sic\ will use a suitable default derived from
 the initialisation file when the checker file does not exist.
\end{itemize}
Tasks and their associated files are searched for in the \texttt{task\#dir:}
search path (by default \texttt{``./;gag\_tasks:''}).

The structure of the program should always be the same :
\begin{itemize}
\item An input parameters definition part. No image creation or access
  should be made before all parameters are defined.
\item An input and output image mapping part. If possible all necessary
  images should be defined in this part.
\item One or more subroutines performing the processing. No new image
  should be created or accessed in the subroutines. The subroutines should
  preferably not make any reference to any common.
\item A cleanup part. An error status should be returned to the system in
  case of error through a call to {\tt SYSEXI}.
\end{itemize}

\section{A Template Task}

The following program is a typical task with two input images and an output
one. The easiest way to create a new task is just to start with this
working template and modify what is needed.

Note that this sample task uses integer of kind=4, i.e. 32-bit numbers,
to handle some dimensions, so it will be limited to $< 2$ Gbyte data
size. Changing to kind=8 (in main program and subroutines...) would
remove this limitation.
 
\subsection{Source code}
\begin{verbatim}
program combine
  !----------------------------------------------------------------------
  ! GILDAS Combine in different ways two input images
  !        (or data cubes)...
  !----------------------------------------------------------------------
  use image_def
  use gkernel_interfaces
  use gbl_format
  !
  character(len=filename_length) :: 80 namex,namey,namez
  character(len=20) :: code
  logical error
  real ay,az,ty,tz,b,c
  type (gildas) :: hx, hy, hz
  real, allocatable :: dx(:,:), dy(:,:), dz(:)
  integer(kind=4) :: i, j, n, m
  integer :: ier
  !
  call gildas_open
  call gildas_char('Z_NAME$',namez)
  call gildas_real('Z_FACTOR$',az,1)
  call gildas_real('Z_MIN$',tz,1)
  call gildas_char('Y_NAME$',namey)
  call gildas_real('Y_FACTOR$',ay,1)
  call gildas_real('Y_MIN$',ty,1)
  call gildas_char('X_NAME$',namex)
  call gildas_real('BLANKING$',b,1)
  call gildas_real('OFFSET$',c,1)
  call gildas_char('FUNCTION$',code)
  call gildas_close
  !
  n = len_trim(namez)
  if (n.eq.0) goto 100
  call gildas_null(hz)
  call sic_parsef(namez(1:n),hz%file,' ','.gdf')
  call gdf_read_header(hz,error)
  if (error) then
    call gagout('F-COMBINE,  Cannot read input file')
    goto 100
  endif
  !
  n = len_trim(namey)
  if (n.eq.0) goto 100
  call gildas_null(hy)
  call sic_parsef(namey(1:n),hy%file,' ','.gdf')
  call gdf_read_header(hy,error)
  if (error) then
    call gagout('F-COMBINE,  Cannot read input file')
    goto 100
  endif
  !
  if (hz%gil%eval.ge.0.0) hz%gil%eval =   &
    max(hz%gil%eval,abs(hz%gil%bval*1e-7))
  if (hy%gil%eval.ge.0.0) hy%gil%eval =   &
    max(hy%gil%eval,abs(hy%gil%bval*1e-7))
  !
  ! Check input dimensions
  do i=1,gdf_maxdims
    if (hy%gil%dim(i).ne.hz%gil%dim(i)) then
      n = 1
      do j=i,gdf_maxdims
        n = n*hz%gil%dim(j)
      enddo
      if (n.ne.1) then
        call gagout('F-COMBINE,  Input images are non coincident')
        goto 100
      else
        call gagout('W-COMBINE,  Combining a cube with a plane')
      endif
    endif
  enddo
  !
  call gdf_copy_header(hy,hx)
  n = len_trim(namex)
  if (n.eq.0) goto 100
  call sic_parsef(namex(1:n),hx%file,' ','.gdf')
  hx%gil%blan_words = 2
  hx%gil%bval = b
  hx%gil%eval = 0.0
  hx%gil%extr_words = 0  ! No extrema computed
  !
  ! Allocate the arrays. Note that the allocated arrays do not conform
  ! to the shape of the images: DZ is allocated as a 1-D array, DX,DY
  ! as 2-D arrays, possibly of second dimension 1.
  !
  n = hz%loca%size
  m = hx%loca%size/hz%loca%size
  allocate(dx(n,m),dy(n,m),dz(n),stat=ier)
  if (ier.ne.0) then
    call gagout('F-COMBINE,  Input images are non coincident')
    goto 100
  endif
  !
  ! Read the input data
  call gdf_read_data(hz,dz,error)
  call gdf_read_data(hy,dy,error)
  !
  if (code.eq.'ADD') then
    call add002(dz,dy,dx,   &
      n,m,   &
      hz%gil%bval,hz%gil%eval,az,tz,   &
      hy%gil%bval,hy%gil%eval,ay,ty,   &
      hx%gil%bval,c)
  elseif (code.eq.'DIVIDE') then
    call div002(dz,dy,dx,   &
      n,m,   &
      hz%gil%bval,hz%gil%eval,az,tz,   &
      hy%gil%bval,hy%gil%eval,ay,ty,   &
      hx%gil%bval,c)
  elseif (code.eq.'MULTIPLY') then
    call mul002(dz,dy,dx,   &
      n,m,   &
      hz%gil%bval,hz%gil%eval,az,tz,   &
      hy%gil%bval,hy%gil%eval,ay,ty,   &
      hx%gil%bval,c)
  elseif (code.eq.'OPTICAL_DEPTH') then
    call opt002(dz,dy,dx,   &
      n,m,   &
      hz%gil%bval,hz%gil%eval,az,tz,   &
      hy%gil%bval,hy%gil%eval,ay,ty,   &
      hx%gil%bval,c)
  else
    call gagout('Invalid operation code '//code)
    goto 100
  endif
  !
  ! Write ouput file
  call gdf_write_image(hx,dx,error)
  !
  stop 'S-COMBINE,  Successful completion'
  !
  100     call sysexi (fatale)
end
!
subroutine add002(z,y,x,n,m,bz,ez,az,tz,by,ey,ay,ty,bx,c)
  !---------------------------------------------------------------------
  ! GDF Internal routine
  !     Linear combination of input arrays
  !     X = Ay*Y + Az*Z + C
  ! Arguments
  !     Z               R*4(*)  Input array (N)
  !     Y               R*4(*)  Input array (N,M)
  !     X               R*4(*)  Output array (N,M)
  !     N,M             I       Dimensions of arrays
  !     BX,BY,BZ        R*4     Blanking values
  !     EY,EZ           R*4     Tolerance on blanking
  !     AZ,AY           R*4     Multiplicative factor of array Z, Y
  !     TZ,TY           R*4     Threshold on Z,Y
  !     C               R*4     Additive constant
  !---------------------------------------------------------------------
  integer :: n                      !
  real :: z(n)                      !
  integer :: m                      !
  real :: y(n,m)                    !
  real :: x(n,m)                    !
  real :: bz                        !
  real :: ez                        !
  real :: az                        !
  real :: tz                        !
  real :: by                        !
  real :: ey                        !
  real :: ay                        !
  real :: ty                        !
  real :: bx                        !
  real :: c                         !
  ! Local
  integer :: i,k
  !
  do k=1,m
    do i=1,n
      if (abs(z(i)-bz).gt.ez .and. abs(y(i,k)-by).gt.ey   &
     &        .and. z(i).gt.tz .and. y(i,k).gt.ty) then
        x(i,k) = ay*y(i,k) + az*z(i)  +  c
      else
        x(i,k) = bx
      endif
    enddo
  enddo
end
\end{verbatim}

\subsection{Initialization file}

The initialization file is a standard \sic\ procedure containing only
commands from the languages {\tt TASK$\backslash$} or {\tt
  SIC$\backslash$}.  {\tt TASK$\backslash$} language must be specified
explicitly.
The command syntax is always the following \\
{\tt \hskip 2.0cm TASK$\backslash$Type\_of\_parameter "Prompt string"
  Parameter\$[Dimension]}

where
\begin{itemize}
\item {\tt Type\_of\_Parameter} can be {\tt CHARACTER, REAL, INTEGER or
    LOGICAL}
\item {\tt "Prompt string"} is a text used as a prompt if required
\item {\tt Parameter\$} is the parameter name, the parameter being a
  standard \sic\ variable, possibly with one dimension. It is recommended
  to include a {\tt \$} as last character to avoid possible confusion with
  user declared variables.
\end{itemize}

\begin{verbatim}
!
! Combine.INIT
TASK\FILE "First input map" Z_NAME$
TASK\REAL "Scaling factor" Z_FACTOR$
TASK\REAL "Threshold" Z_MIN$
TASK\FILE "Second input map" Y_NAME$
TASK\REAL "Scaling factor" Y_FACTOR$
TASK\REAL "Threshold" Y_MIN$
TASK\FILE "Output map" X_NAME$
TASK\REAL "New blanking value" BLANKING$
TASK\REAL "Output offset" OFFSET$
TASK\CHARACTER "Function" FUNCTION$
TASK\GO                     ! Must be last command
\end{verbatim}
The parameter names, types and dimensions must correspond to those declared
in the source code. All parameters must be defined.  Ordering may be
important (see Checker File).


\subsection{The HELP file}

A standard help file should be prepared for each task. The format follows
that of \sic\ help files. Topics are identified by a ``1'' in first column,
and subtopics by a ``2''.  The help file must start with the task name as
main topic, and must have a subtopic for each parameter.  More subtopics
may exist. The help file must be in the same place as the executable image,
and have file type {\tt .hlp}.  For the example above, {\tt combine.hlp}
contains

\begin{verbatim}
1 COMBINE
                               COMBINE

     It makes "combinations" of two input images to  produce  a  third
one.   The two input images may have the same dimensions, or the first
one (Z one) may have less dimensions than the second (Y) one.  In  the
latter case, combinations will occur for all the extra planes of the Y
image.  For example you can divide all the plane of an input  (Y)  3-D
cube  by  a 2-D (Z) image, provided each plane of the cube matches the
single image...

     Operations are
        ADD             X = Ay*Y + Az*Z + C
        MULTIPLY        X = Ay*Y * Az*Z + C
        DIVIDE          X = Ay*Y / Az*Z + C
provided Y > Ty and Z > Tz, where Ty and Tz and thresholds
set by parameters YMIN$ and ZMIN$.

2  Z_NAME$
This is the  name  of  the  input  map  with  the  smaller  number  of
dimensions.
2  Z_FACTOR$
This is a scaling factor for map Z_NAME$.
2  Z_MIN$
This is a threshold on map Z_NAME$.
2  Y_NAME$
This is  the  name  of  the  input  map  with  the  larger  number  of
dimensions.
2  Y_FACTOR$
This is a scaling factor for map Y_NAME$.
2  Y_MIN$
This is a threshold on map Y_NAME$.
2  X_NAME$
This is the name of the output map.
2  BLANKING$
This is the blanking value chosen for the output map.
2  OFFSET$
This is an offset added to the output map.
2  FUNCTION$
Selected operation.  Possible operations are ADD, MULTIPLY, DIVIDE  (Y
by Z).
\end{verbatim}
%$

\subsection{Checker File}

The checker file is optional. If it does not exist, \sic\ will create one
writing all the task input variables in the order in which they have
been defined.

The checker file is another \sic\ procedure containing only {\tt
  TASK$\backslash$} and {\tt SIC$\backslash$} commands, which tests the
validity of the input parameters (to avoid submission of tasks with bad
parameters), and writes the parameters. Checking is optional and can be
done using \sic\ facilities. All parameters are known \sic\ variables.
Writing is done using command {\tt TASK$\backslash$WRITE}, and the ordering
must match the source code. The task is initiated by the {\tt
  TASK$\backslash$GO} command.
\begin{verbatim}
!
! Combine.CHECK
SIC\IF (FUNCTION$.EQ."ADD") THEN
    SIC\SAY "Computing X_NAME = -
    'Y_FACTOR$'*Y_NAME + 'Z_FACTOR$'*Z_NAME + 'OFFSET$'"
SIC\ELSE IF (FUNCTION$.EQ."DIVIDE") THEN
    SIC\SAY "Computing X_NAME = -
    'Y_FACTOR$'*Y_NAME / 'Z_FACTOR$'*Z_NAME + 'OFFSET$'"
SIC\ELSE IF (FUNCTION$.EQ."MULTIPLY") THEN
    SIC\SAY "Computing X_NAME = -
    'Y_FACTOR$'*Y_NAME * 'Z_FACTOR$'*Z_NAME + 'OFFSET$'"
SIC\ELSE
    SIC\SAY "Invalid operation 'FUNCTION$'"
    SIC\RETURN   ! Return without a GO command : no submission
SIC\ENDIF
!
TASK\WRITE Z_NAME$
TASK\WRITE Z_FACTOR$
TASK\WRITE Z_MIN$
TASK\WRITE Y_NAME$
TASK\WRITE Y_FACTOR$
TASK\WRITE Y_MIN$
TASK\WRITE X_NAME$
TASK\WRITE BLANKING$
TASK\WRITE OFFSET$
TASK\WRITE FUNCTION$
TASK\GO                     ! Effectively RUNs or SUBMITs the task.
\end{verbatim}



\section{Debugging Tasks}

In addition to the predefined directory, {\tt GILDAS\_RUN:}, another
directory {\tt GILDAS\_LOCAL:} is also searched for tasks by commands {\tt
  VECTOR$\backslash$RUN} and {\tt VECTOR$\backslash$SUBMIT}. This area is
searched before {\tt GILDAS\_RUN:}. If the required task is found here, the
initialisation, checker and help files should also be present in the same
directory.  This feature allows to have experimental or user-private tasks.

Although the tasks are supposed to be non-interactive programs spawned or
submitted from a main program, interactive use is possible for debugging
purpose.  If activated interactively, a task will ask one question for each
parameter, specifying the parameter type, the parameter name, and the
parameter dimension. No more information will be available.  The
initialization and checker file are not needed for this.

Moreover since all algorithms can be standard subroutines due to the use of
virtual memory, the \gildas\ interface can be done easily after debugging
the algorithm.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gildas-prog"
%%% End:
