IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 17911


Ignore:
Timestamp:
Jun 4, 2008, 3:32:28 PM (18 years ago)
Author:
Paul Price
Message:

I've implemented the chip-dependent concepts. It uses a generalised version of the dependent DEFAULT concepts, which can, unfortunately, make the camera format configuration a bit longer, but it consolidates code and keeps things simple both for the code and the configuration.

In the process, I took care of a couple of other concept bugs that have been sitting in my inbox for nearly a year:

  • FPA.NAME has been replaced with FPA.OBS, which is intended to be an observation identifier (bug 885). You're welcome to change the name, so long as you also volunteer to fix all the camera formats.
  • FPA.CAMERA is automatically set (on construction of the FPA) to the camera name as used by the configuration files (bug 931). I've changed the ppStats REGISTER recipe to use FPA.CAMERA instead of FPA.INSTRUMENT (which is retained in the concepts as the instrument's name according to the instrument, whereas FPA.CAMERA is the instrument's name according to our configuration).
Location:
trunk
Files:
49 edited

Legend:

Unmodified
Added
Removed
  • trunk/ippconfig/cfh12k/format_mef.config

    r15550 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     CHIP    # The extensions represent chips
    16         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     16        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1717        CHIP.NAME       STR     IMAGEID # An extension keyword for unique identifie
    1818        EXTWORD         STR     IMAGEID
  • trunk/ippconfig/cfh12k/format_mef_early.config

    r16808 r17911  
    1818        PHU             STR     FPA     # The FITS file represents an entire FPA
    1919        EXTENSIONS      STR     CHIP    # The extensions represent chips
    20         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     20        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    2121        CHIP.NAME       STR     IMAGEID # An extension keyword for unique identifie
    2222        EXTWORD         STR     IMAGEID
  • trunk/ippconfig/cfh12k/format_split.config

    r15550 r17911  
    1414        PHU             STR     CHIP     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE     # The extensions represent chips
    16         FPA.NAME        STR     EXPNUM   # A PHU keyword for unique identifier
     16        FPA.OBS         STR     EXPNUM   # A PHU keyword for unique identifier
    1717        CHIP.NAME       STR     IMAGEID  # An extension keyword for unique identifie
    1818        EXTWORD         STR     IMAGEID
  • trunk/ippconfig/cfh12k/format_split_cmf.config

    r17294 r17911  
    1414        PHU             STR     CHIP     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE     # The extensions represent chips
    16         FPA.NAME        STR     EXPNUM   # A PHU keyword for unique identifier
     16        FPA.OBS         STR     EXPNUM   # A PHU keyword for unique identifier
    1717        CHIP.NAME       STR     IMAGEID  # An extension keyword for unique identifie
    1818        EXTWORD         STR     IMAGEID
  • trunk/ippconfig/cfh12k/format_split_early.config

    r15550 r17911  
    1818        PHU             STR     CHIP    # The FITS file represents an entire FPA
    1919        EXTENSIONS      STR     NONE    # The extensions represent chips
    20         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     20        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    2121        CHIP.NAME       STR     IMAGEID # An extension keyword for unique identifie
    2222        EXTWORD         STR     IMAGEID
  • trunk/ippconfig/ctio_mosaic2/format.config

    r13865 r17911  
    1313        PHU             STR     FPA      # The FITS file represents an entire FPA
    1414        EXTENSIONS      STR     CELL     # The extensions represent cells
    15         FPA.NAME        STR     FILENAME # A PHU keyword for unique identifier within the hierarchy level
     15        FPA.OBS STR     FILENAME # A PHU keyword for unique identifier within the hierarchy level
    1616END
    1717
  • trunk/ippconfig/esowfi/format_split.config

    r15309 r17911  
    1111        PHU             STR     CHIP            # The FITS file represents an entire FPA
    1212        EXTENSIONS      STR     NONE            # There are no extensions
    13         FPA.NAME        STR     ORIGIN          # A PHU keyword for unique FPA identifier
     13        FPA.OBS         STR     ORIGIN          # A PHU keyword for unique FPA identifier
    1414        CONTENT         STR     EXTNAME         # Key to the CONTENTS menu
    1515        CONTENT.RULE    STR     {CHIP.NAME}     # How to derive the CONTENT when writing
  • trunk/ippconfig/esowfi/format_together.config

    r15309 r17911  
    1212        PHU             STR             FPA             # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR             CHIP            # There are no extensions
    14         FPA.NAME        STR             ESO OBS NAME    # A PHU keyword for unique FPA identifier
     14        FPA.OBS         STR             ESO OBS NAME    # A PHU keyword for unique FPA identifier
    1515END
    1616
  • trunk/ippconfig/gpc1/format_mef.config

    r15949 r17911  
    1313        PHU             STR     FPA        # The FITS file represents a complete camera fpa
    1414        EXTENSIONS      STR     CHIP       # The extensions represent chips
    15         FPA.NAME        STR     CONTROLR   # A PHU keyword for unique identifier within the hierarchy level
     15        FPA.OBS         STR     CONTROLR   # A PHU keyword for unique identifier within the hierarchy level
    1616END
    1717
     
    196196        FPA.INSTRUMENT  STR     GPC1
    197197        FPA.DETECTOR    STR     GPC1
    198         FPA.NAME        S32     12345
     198        FPA.OBS S32     12345
    199199        FPA.TIMESYS     STR     UTC
    200200        CHIP.XPARITY    S32     1
  • trunk/ippconfig/gpc1/format_raw.config

    r17100 r17911  
    1414        PHU             STR     CHIP       # The FITS file represents a single chip
    1515        EXTENSIONS      STR     CELL       # The extensions represent cells
    16         FPA.NAME        STR     CONTROLR   # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS         STR     CONTROLR   # A PHU keyword for unique identifier within the hierarchy level
    1717        CONTENT         STR     DETECTOR   # How to determine content of FITS file
    1818        CONTENT.RULE    STR     {CHIP.ID}  # How to derive the CONTENT when writing
     
    214214        CELL.YPARITY    STR     LTM2_2
    215215#       CELL.SATURATION STR     SATURATE
    216         CHIP.TEMP       STR     DETTEM
     216
     217#        CHIP.TEMP       STR     DETTEM # XY24 is bad, so get it from the database; all others from header
     218        CHIP.TEMP.DEPEND        STR     CHIP.NAME
     219        CHIP.TEMP       METADATA
     220                XY01    STR     DETTEM
     221                XY02    STR     DETTEM
     222                XY03    STR     DETTEM
     223                XY04    STR     DETTEM
     224                XY05    STR     DETTEM
     225                XY06    STR     DETTEM
     226                XY10    STR     DETTEM
     227                XY11    STR     DETTEM
     228                XY12    STR     DETTEM
     229                XY13    STR     DETTEM
     230                XY14    STR     DETTEM
     231                XY15    STR     DETTEM
     232                XY16    STR     DETTEM
     233                XY17    STR     DETTEM
     234                XY20    STR     DETTEM
     235                XY21    STR     DETTEM
     236                XY22    STR     DETTEM
     237                XY23    STR     DETTEM
     238#               XY24    STR     DETTEM  # This is currently bad --- get it from the database
     239                XY25    STR     DETTEM
     240                XY26    STR     DETTEM
     241                XY27    STR     DETTEM
     242                XY30    STR     DETTEM
     243                XY31    STR     DETTEM
     244                XY32    STR     DETTEM
     245                XY33    STR     DETTEM
     246                XY34    STR     DETTEM
     247                XY35    STR     DETTEM
     248                XY36    STR     DETTEM
     249                XY37    STR     DETTEM
     250                XY40    STR     DETTEM
     251                XY41    STR     DETTEM
     252                XY42    STR     DETTEM
     253                XY43    STR     DETTEM
     254                XY44    STR     DETTEM
     255                XY45    STR     DETTEM
     256                XY46    STR     DETTEM
     257                XY47    STR     DETTEM
     258                XY50    STR     DETTEM
     259                XY51    STR     DETTEM
     260                XY52    STR     DETTEM
     261                XY53    STR     DETTEM
     262                XY54    STR     DETTEM
     263                XY55    STR     DETTEM
     264                XY56    STR     DETTEM
     265                XY57    STR     DETTEM
     266                XY60    STR     DETTEM
     267                XY61    STR     DETTEM
     268                XY62    STR     DETTEM
     269                XY63    STR     DETTEM
     270                XY64    STR     DETTEM
     271                XY65    STR     DETTEM
     272                XY66    STR     DETTEM
     273                XY67    STR     DETTEM
     274                XY71    STR     DETTEM
     275                XY72    STR     DETTEM
     276                XY73    STR     DETTEM
     277                XY74    STR     DETTEM
     278                XY75    STR     DETTEM
     279                XY76    STR     DETTEM
     280        END
     281
    217282        FPA.EXPOSURE    STR     EXPREQ          # Requested exposure time, presumably camera exposure time
    218283        CELL.EXPOSURE   STR     EXPTIME         # Exposure time measured by shutter
     
    225290        FPA.INSTRUMENT  STR     GPC1
    226291        FPA.DETECTOR    STR     GPC1
    227         FPA.NAME        S32     12345
    228292        FPA.TIMESYS     STR     UTC
    229293        CHIP.XPARITY    S32     1
     
    492556# How to translation PS concepts into database lookups
    493557DATABASE        METADATA
    494         TYPE            dbEntry         TABLE           COLUMN          GIVENDBCOL      GIVENPS
    495 #       CELL.GAIN       dbEntry         Camera          gain            chipId,cellId   CHIP,CELL
    496 #       CELL.READNOISE  dbEntry         Camera          readNoise       chipId,cellId   CHIP,CELL
    497 
    498 # A database entry refers to a particular column (COLUMN) in a
    499 # particular table (TABLE), given certain PS concepts (GIVENPS) that
    500 # match certain database columns (GIVENDBCOL).
    501 
     558        CHIP.TEMP.DEPEND        STR     CHIP.NAME
     559        CHIP.TEMP               METADATA
     560                XY24    STR     SELECT AVG(ccd_temp) FROM rawImfile WHERE dateobs = '{FPA.TIME}' AND class_id != 'XY24'
     561        END
    502562END
    503563
  • trunk/ippconfig/isp/format.config

    r13601 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE    # There are no extensions
    16         FPA.NAME        STR     SEQID   # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS STR     SEQID   # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
  • trunk/ippconfig/lbc_red/format.config

    r17154 r17911  
    1515        PHU             STR     FPA     # The FITS file represents an entire FPA
    1616        EXTENSIONS      STR     CHIP    # The extensions represent chips
    17         FPA.NAME        STR     OBS_ID  # A PHU keyword for unique identifier
     17        FPA.OBS STR     OBS_ID  # A PHU keyword for unique identifier
    1818        CHIP.NAME       STR     EXTNAME # An extension keyword for unique identifie
    1919END
  • trunk/ippconfig/lris_blue/format_mef.config

    r6869 r17911  
    1212        PHU             STR     FPA     # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     CHIP    # There are no extensions
    14         FPA.NAME        STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
     14        FPA.OBS         STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
    1515END
    1616
  • trunk/ippconfig/lris_blue/format_raw.config

    r6869 r17911  
    3333        PHU             STR     FPA     # The FITS file represents an entire FPA
    3434        EXTENSIONS      STR     NONE    # There are no extensions
    35         FPA.NAME        STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
     35        FPA.OBS         STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
    3636END
    3737
  • trunk/ippconfig/lris_red/format_raw.config

    r7100 r17911  
    3434        PHU             STR     FPA     # The FITS file represents a single chip
    3535        EXTENSIONS      STR     NONE    # There are no extensions
    36         FPA.NAME        STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
     36        FPA.OBS         STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
    3737END
    3838
  • trunk/ippconfig/lris_red/format_spec.config

    r7100 r17911  
    3434        PHU             STR     FPA     # The FITS file represents a single chip
    3535        EXTENSIONS      STR     NONE    # There are no extensions
    36         FPA.NAME        STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
     36        FPA.OBS         STR     OBSNUM  # A PHU keyword for unique identifier within the hierarchy level
    3737        CHIP.NAME       STR     INSTRUME        # An extension keyword for unique identifier
    3838END
  • trunk/ippconfig/mcshort/format_raw.config

    r9512 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     CELL    # The extensions represent cells
    16         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
     
    118118# How to translate PS concepts into FITS headers
    119119TRANSLATION     METADATA
    120         FPA.NAME                STR     EXPNUM
     120        FPA.OBS         STR     EXPNUM
    121121        FPA.AIRMASS             STR     AIRMASS
    122122        FPA.FILTER              STR     FILTER
  • trunk/ippconfig/mcshort/format_spliced.config

    r12565 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     CHIP    # The extensions represent chips
    16         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     16        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1717        CHIP.NAME       STR     EXTNAME # An extension keyword for unique identifie
    1818END
     
    9090# How to translate PS concepts into FITS headers
    9191TRANSLATION     METADATA
    92         FPA.NAME        STR     EXPNUM
     92        FPA.OBS        STR     EXPNUM
    9393        FPA.AIRMASS     STR     AIRMASS
    9494        FPA.FILTER      STR     FILTER
  • trunk/ippconfig/mcshort/format_split.config

    r15064 r17911  
    1212        PHU             STR     CHIP    # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     NONE    # The extensions represent chips
    14         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     14        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1515        CONTENT         STR     EXTNAME # Key to the CONTENTS menu
    1616END
     
    8888# How to translate PS concepts into FITS headers
    8989TRANSLATION     METADATA
    90         FPA.NAME        STR     EXPNUM
     90        FPA.OBS        STR     EXPNUM
    9191        FPA.AIRMASS     STR     AIRMASS
    9292        FPA.FILTER      STR     FILTER
  • trunk/ippconfig/megacam/format_mef.config

    r17875 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     CHIP    # The extensions represent chips
    16         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     16        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1717        # CHIP.NAME     STR     EXTNAME # An extension keyword for unique identifie
    1818END
  • trunk/ippconfig/megacam/format_pre_03Am04_mef.config

    r16644 r17911  
    1313        PHU             STR     FPA     # The FITS file represents an entire FPA
    1414        EXTENSIONS      STR     CHIP    # The extensions represent chips
    15         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     15        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1616        # CHIP.NAME     STR     EXTNAME # An extension keyword for unique identifie
    1717END
  • trunk/ippconfig/megacam/format_pre_03Am04_raw.config

    r16644 r17911  
    1313        PHU             STR     FPA     # The FITS file represents an entire FPA
    1414        EXTENSIONS      STR     CELL    # The extensions represent cells
    15         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
     15        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
    1616END
    1717
  • trunk/ippconfig/megacam/format_raw.config

    r16644 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     CELL    # The extensions represent cells
    16         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
  • trunk/ippconfig/megacam/format_split.config

    r15095 r17911  
    1212        PHU             STR     CHIP    # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     NONE    # The extensions represent chips
    14         FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
     14        FPA.OBS         STR     EXPNUM  # A PHU keyword for unique identifier
    1515        CONTENT         STR     EXTNAME # Key to the CONTENTS menu
    1616        CONTENT.RULE    STR     {CHIP.NAME} # How to derive the CONTENT when writing
     
    9191# How to translate PS concepts into FITS headers
    9292TRANSLATION     METADATA
    93         FPA.NAME        STR     EXPNUM
     93        FPA.OBS        STR     EXPNUM
    9494        FPA.AIRMASS     STR     AIRMASS
    9595        FPA.FILTER      STR     FILTER
  • trunk/ippconfig/mosaic2/format.config

    r17735 r17911  
    1313        PHU             STR     FPA      # The FITS file represents an entire FPA
    1414        EXTENSIONS      STR     CELL     # The extensions represent cells
    15         FPA.NAME        STR     FILENAME # A PHU keyword for unique identifier within the hierarchy level
     15        FPA.OBS STR     FILENAME # A PHU keyword for unique identifier within the hierarchy level
    1616END
    1717
  • trunk/ippconfig/recipes/ppStats.config

    r16254 r17911  
    8181  CONCEPT       STR     FPA.TIME        # Time of exposure
    8282  CONCEPT       STR     FPA.TELESCOPE   # Telescope (eg, CFHT)
    83   CONCEPT       STR     FPA.INSTRUMENT  # Instrument (eg, CFH12K)
     83  CONCEPT       STR     FPA.CAMERA      # Instrument (eg, CFH12K)
    8484  CONCEPT       STR     CHIP.TEMP       # Detector temperature
    8585  CONCEPT       STR     CELL.EXPOSURE   # Exposure time
  • trunk/ippconfig/sdss/format.config

    r14553 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE    # There are no extensions
    16         FPA.NAME        STR     FRAME   # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS STR     FRAME   # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
  • trunk/ippconfig/sdss/format_skycell.config

    r14553 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE    # There are no extensions
    16         FPA.NAME        STR     FRAME   # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS         STR     FRAME   # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
  • trunk/ippconfig/simmosaic/format_split.config

    r15095 r17911  
    1212        PHU             STR     CHIP            # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     CELL            # There are no extensions
    14         FPA.NAME        STR     FPANAME         # A PHU keyword for unique FPA identifier
     14        FPA.OBS         STR     FPANAME         # A PHU keyword for unique FPA identifier
    1515        CONTENT         STR     CHIPNAME        # How to determine content of FITS file
    1616        CONTENT.RULE    STR     {CHIP.NAME}     # How to derive the CONTENT when writing
  • trunk/ippconfig/simmosaic/format_together.config

    r15064 r17911  
    1212        PHU             STR     FPA             # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     CHIP            # There are no extensions
    14         FPA.NAME        STR     FPANAME         # A PHU keyword for unique FPA identifier
     14        FPA.OBS         STR     FPANAME         # A PHU keyword for unique FPA identifier
    1515        CONTENT         STR     CHIPNAME        # How to determine content of FITS file
    1616END
  • trunk/ippconfig/simple/format.config

    r13110 r17911  
    1111        PHU             STR     FPA     # The FITS file represents an entire FPA
    1212        EXTENSIONS      STR     NONE    # There are no extensions
    13         FPA.NAME        STR     NAXIS   # A PHU keyword for unique identifier within the hierarchy level
     13        FPA.OBS         STR     NAXIS   # A PHU keyword for unique identifier within the hierarchy level
    1414END
    1515
  • trunk/ippconfig/simtest/format.config

    r16220 r17911  
    1212        PHU             STR     FPA     # The FITS file represents an entire FPA
    1313        EXTENSIONS      STR     NONE    # There are no extensions
    14         FPA.NAME        STR     OBJECT  # A PHU keyword for unique identifier within the hierarchy level
     14        FPA.OBS STR     OBJECT  # A PHU keyword for unique identifier within the hierarchy level
    1515END
    1616
  • trunk/ippconfig/tc3/format.config

    r15095 r17911  
    1313        PHU             STR     CHIP    # The FITS file represents a chip
    1414        EXTENSIONS      STR     CELL    # The extensions represent cells
    15         FPA.NAME        STR     OBSTYPE # A PHU keyword for unique identifier
     15        FPA.OBS STR     OBSTYPE # A PHU keyword for unique identifier
    1616        CONTENT         STR     DETECTOR # How to determine content of FITS file
    1717        CONTENT.RULE    STR     {CHIP.NAME}     # How to derive the CONTENT when writing
  • trunk/ippconfig/tek/format.config

    r14564 r17911  
    1414        PHU             STR     FPA     # The FITS file represents an entire FPA
    1515        EXTENSIONS      STR     NONE    # There are no extensions
    16         FPA.NAME        STR     NAXIS   # A PHU keyword for unique identifier within the hierarchy level
     16        FPA.OBS STR     NAXIS   # A PHU keyword for unique identifier within the hierarchy level
    1717END
    1818
  • trunk/ippconfig/ucam/format_raw.config

    r9716 r17911  
    1313        PHU             STR     FPA     # The FITS file represents an entire FPA
    1414        EXTENSIONS      STR     CELL    # The extensions represent cells
    15         FPA.NAME        STR     OBSTYPE # A PHU keyword for unique identifier within the hierarchy level
     15        FPA.OBS         STR     OBSTYPE # A PHU keyword for unique identifier within the hierarchy level
    1616END
    1717
  • trunk/psModules/src/camera/pmFPA.c

    r16716 r17911  
    305305    tmpCell->conceptsRead = PM_CONCEPT_SOURCE_NONE;
    306306    if (!psMetadataAddStr(tmpCell->concepts, PS_LIST_HEAD, "CELL.NAME", 0, NULL, name)) {
    307         psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not add CELL.NAME to metadata.\n");
     307        psErrorClear();
     308        psWarning("Could not add CELL.NAME to metadata.");
    308309    }
    309310    pmConceptsBlankCell(tmpCell);
     
    343344    tmpChip->conceptsRead = PM_CONCEPT_SOURCE_NONE;
    344345    if (!psMetadataAddStr(tmpChip->concepts, PS_LIST_HEAD, "CHIP.NAME", 0, NULL, name)) {
    345         psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not add CHIP.NAME %s to concepts.\n", name);
     346        psErrorClear();
     347        psWarning("Could not add CHIP.NAME %s to concepts.", name);
    346348    }
    347349    pmConceptsBlankChip(tmpChip);
     
    355357}
    356358
    357 pmFPA *pmFPAAlloc(const psMetadata *camera)
     359pmFPA *pmFPAAlloc(const psMetadata *camera, const char *cameraName)
    358360{
    359361    pmFPA *tmpFPA = (pmFPA *) psAlloc(sizeof(pmFPA));
     
    373375    pmConceptsBlankFPA(tmpFPA);
    374376
     377    if (!psMetadataAddStr(tmpFPA->concepts, PS_LIST_TAIL, "FPA.CAMERA", PS_META_REPLACE,
     378                          "Camera name (according to configuration)", cameraName)) {
     379        psErrorClear();
     380        psWarning("Could not add FPA.CAMERA %s to concepts.", cameraName);
     381    }
     382
    375383    return tmpFPA;
    376384}
  • trunk/psModules/src/camera/pmFPA.h

    r17249 r17911  
    66 * @author Eugene Magnier, IfA
    77 *
    8  * @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
    9  * @date $Date: 2008-03-31 22:39:06 $
     8 * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
     9 * @date $Date: 2008-06-05 01:31:33 $
    1010 * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
    1111 */
     
    169169
    170170/// Allocate an FPA
    171 pmFPA *pmFPAAlloc(const psMetadata *camera); ///< Camera configuration (to store in FPA)
     171pmFPA *pmFPAAlloc(const psMetadata *camera, ///< Camera configuration (to store in FPA)
     172                  const char *cameraName ///< Name of camera (for FPA.CAMERA concept)
     173    );
    172174bool psMemCheckFPA(psPtr ptr);
    173175
  • trunk/psModules/src/camera/pmFPAConstruct.c

    r16912 r17911  
    11021102// It returns a view corresponding to the PHU
    11031103static pmFPAview *addSource(pmFPA *fpa,       // The FPA
    1104                             const char *fpaname, // The desired FPA name
     1104                            const char *fpaObs, // The desired FPA observation name
    11051105                            const pmFPAview *phuView, // The view corresponding to the PHU, or NULL
    11061106                            const psMetadata *header, // The PHU header, or NULL
     
    11151115    bool mdok;                          // Status of MD lookup
    11161116
    1117     // If FPA.NAME is already defined, new name must match it; otherwise, warn the user that something
     1117    // If FPA.OBS is already defined, new name must match it; otherwise, warn the user that something
    11181118    // potentially bad is happening.
    1119     if (fpaname && install) {
    1120         const char *currentName = psMetadataLookupStr(&mdok, fpa->concepts, "FPA.NAME"); // Current name
    1121         if (mdok && currentName && strlen(currentName) > 0 && strcmp(currentName, fpaname) != 0) {
    1122             psWarning("FPA.NAME for new source (%s) doesn't match FPA.NAME for current "
    1123                      "fpa (%s).\n", fpaname, currentName);
    1124         }
    1125         psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.NAME", PS_META_REPLACE, "Name of FPA", fpaname);
    1126     } else if (!psMetadataLookup(fpa->concepts, "FPA.NAME")) {
    1127         // Make sure there is an FPA.NAME
    1128         psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.NAME", 0, "Name of FPA", "UNKNOWN");
     1119    if (fpaObs && install) {
     1120        const char *currentName = psMetadataLookupStr(&mdok, fpa->concepts, "FPA.OBS"); // Current name
     1121        if (mdok && currentName && strlen(currentName) > 0 && strcmp(currentName, fpaObs) != 0) {
     1122            psWarning("FPA.OBS for new source (%s) doesn't match FPA.OBS for current fpa (%s).",
     1123                      fpaObs, currentName);
     1124        }
     1125        psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.OBS", PS_META_REPLACE, "Observation identifier",
     1126                         fpaObs);
     1127    } else if (!psMetadataLookup(fpa->concepts, "FPA.OBS")) {
     1128        // Make sure there is an FPA.OBS
     1129        psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.OBS", 0, "Observation identifier", "UNKNOWN");
    11291130    }
    11301131
     
    13081309//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    13091310
    1310 pmFPA *pmFPAConstruct(const psMetadata *camera)
     1311pmFPA *pmFPAConstruct(const psMetadata *camera, const char *cameraName)
    13111312{
    13121313    PS_ASSERT_PTR_NON_NULL(camera, NULL);
    13131314
    1314     pmFPA *fpa = pmFPAAlloc(camera);    // The FPA to fill out
     1315    pmFPA *fpa = pmFPAAlloc(camera, cameraName);    // The FPA to fill out
    13151316
    13161317    bool mdok = true;                   // Status from MD lookups
     
    13491350}
    13501351
    1351 bool pmFPAAddSourceFromFormat(pmFPA *fpa, const char *fpaname, const psMetadata *format)
     1352bool pmFPAAddSourceFromFormat(pmFPA *fpa, const char *fpaObs, const psMetadata *format)
    13521353{
    13531354    PS_ASSERT_PTR_NON_NULL(fpa, false);
     
    13581359    pmFPAview *view = pmFPAviewAlloc(0);// View for current level
    13591360    if (phuLevel == PM_FPA_LEVEL_FPA) {
    1360         if (!pmFPAAddSourceFromView(fpa, fpaname, view, format)) {
     1361        if (!pmFPAAddSourceFromView(fpa, fpaObs, view, format)) {
    13611362            psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
    13621363            psFree(view);
     
    13671368        while ((chip = pmFPAviewNextChip(view, fpa, 1))) {
    13681369            if (phuLevel == PM_FPA_LEVEL_CHIP) {
    1369                 if (!pmFPAAddSourceFromView(fpa, fpaname, view, format)) {
     1370                if (!pmFPAAddSourceFromView(fpa, fpaObs, view, format)) {
    13701371                    psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
    13711372                    psFree(view);
     
    13761377                while ((cell = pmFPAviewNextCell(view, fpa, 1))) {
    13771378                    if (phuLevel == PM_FPA_LEVEL_CELL) {
    1378                         if (!pmFPAAddSourceFromView(fpa, fpaname, view, format)) {
     1379                        if (!pmFPAAddSourceFromView(fpa, fpaObs, view, format)) {
    13791380                            psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
    13801381                            psFree(view);
     
    13911392}
    13921393
    1393 bool pmFPAAddSourceFromView(pmFPA *fpa, const char *fpaname, const pmFPAview *phuView,
     1394bool pmFPAAddSourceFromView(pmFPA *fpa, const char *fpaObs, const pmFPAview *phuView,
    13941395                            const psMetadata *format)
    13951396{
     
    13981399    PS_ASSERT_PTR_NON_NULL(format, false);
    13991400
    1400     pmFPAview *view = addSource(fpa, fpaname, phuView, NULL, format, true);
     1401    pmFPAview *view = addSource(fpa, fpaObs, phuView, NULL, format, true);
    14011402    bool status = (view != NULL);
    14021403    psFree(view);
     
    14181419
    14191420    // Check the name of the FPA
    1420     psString fpaname = phuNameFromHeader("FPA.NAME", fileInfo, phu); // New name for the FPA
    1421     if (!fpaname || strlen(fpaname) == 0) {
    1422         psWarning("Unable to determine FPA.NAME: check for FPA.NAME in FILE in camera format");
    1423     }
    1424 
    1425     pmFPAview *view = addSource(fpa, fpaname, NULL, phu, format, true); // View of PHU, to return
    1426     psFree(fpaname);
     1421    psString fpaObs = phuNameFromHeader("FPA.OBS", fileInfo, phu); // New observation name for the FPA
     1422    if (!fpaObs || strlen(fpaObs) == 0) {
     1423        psWarning("Unable to determine FPA.OBS: check for FPA.OBS in FILE in camera format");
     1424    }
     1425
     1426    pmFPAview *view = addSource(fpa, fpaObs, NULL, phu, format, true); // View of PHU, to return
     1427    psFree(fpaObs);
    14271428
    14281429    return view;
  • trunk/psModules/src/camera/pmFPAConstruct.h

    r16912 r17911  
    44 * @author Paul Price, IfA
    55 *
    6  * @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
    7  * @date $Date: 2008-03-11 01:27:05 $
     6 * @version $Revision: 1.11 $ $Name: not supported by cvs2svn $
     7 * @date $Date: 2008-06-05 01:31:33 $
    88 * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
    99 */
     
    2121/// as the corresponding values (whitespace separated).  The FPA hierarchy is created devoid of any
    2222/// input/output sources (i.e., HDUs).
    23 pmFPA *pmFPAConstruct(const psMetadata *camera ///< The camera configuration
     23pmFPA *pmFPAConstruct(const psMetadata *camera, ///< The camera configuration
     24                      const char *cameraName ///< Name of the camera (for FPA.CAMERA concept)
    2425                     );
    2526
     
    2829/// This is suitable for generating an output FPA given the desired format.
    2930bool pmFPAAddSourceFromFormat(pmFPA *fpa, ///< The FPA
    30                               const char *fpaname, ///< FPA.NAME for the source
     31                              const char *fpaObs, ///< FPA.NAME for the source
    3132                              const psMetadata *format ///< Format of file
    3233    );
     
    3738/// configuration is required in order to describe how the FPA is laid out in terms of disk files.
    3839bool pmFPAAddSourceFromView(pmFPA *fpa,   ///< The FPA
    39                             const char *fpaname, ///< FPA.NAME for the source
     40                            const char *fpaObs, ///< FPA.NAME for the source
    4041                            const pmFPAview *phuView, ///< The view, corresponding to the PHU
    4142                            const psMetadata *format ///< Format of file
  • trunk/psModules/src/camera/pmFPAWrite.c

    r16396 r17911  
    3737
    3838
    39 // Update the FPA.NAME, CHIP.NAME and CELL.NAME in the FITS header, if required
     39// Update the FPA.OBS, CHIP.NAME and CELL.NAME in the FITS header, if required
    4040bool pmFPAUpdateNames(pmFPA *fpa, pmChip *chip, pmCell *cell)
    4141{
     
    5555    }
    5656    if (fpa) {
    57         const char *fpaNameHdr = psMetadataLookupStr(&mdok, fileData, "FPA.NAME");
    58         if (mdok && fpaNameHdr && strlen(fpaNameHdr) > 0) {
    59             const char *fpaName = psMetadataLookupStr(NULL, fpa->concepts, "FPA.NAME");
    60             psMetadataAddStr(hdu->header, PS_LIST_TAIL, fpaNameHdr, PS_META_REPLACE, "FPA name", fpaName);
     57        const char *fpaObsHdr = psMetadataLookupStr(&mdok, fileData, "FPA.OBS");
     58        if (mdok && fpaObsHdr && strlen(fpaObsHdr) > 0) {
     59            const char *fpaObs = psMetadataLookupStr(NULL, fpa->concepts, "FPA.OBS");
     60            psMetadataAddStr(hdu->header, PS_LIST_TAIL, fpaObsHdr, PS_META_REPLACE,
     61                             "Observation identifier", fpaObs);
    6162        }
    6263    }
  • trunk/psModules/src/camera/pmFPAfile.c

    r17036 r17911  
    181181  newName = psStringCopy(rule);
    182182
    183   if (strstr (newName, "{FPA.NAME}") != NULL) {
    184     char *name = psMetadataLookupStr (NULL, fpa->concepts, "FPA.NAME");
     183  if (strstr (newName, "{FPA.OBS}") != NULL) {
     184    char *name = psMetadataLookupStr (NULL, fpa->concepts, "FPA.OBS");
    185185    if (name != NULL) {
    186       psStringSubstitute(&newName, "fpa", "{FPA.NAME}");
     186      psStringSubstitute(&newName, "fpa", "{FPA.OBS}");
    187187    }
    188188  }
  • trunk/psModules/src/camera/pmFPAfileDefine.c

    r17634 r17911  
    237237        file->fpa = psMemIncrRefCounter(fpa);
    238238    } else {
    239         file->fpa = pmFPAConstruct(file->camera);
     239        file->fpa = pmFPAConstruct(file->camera, file->cameraName);
    240240    }
    241241
     
    482482
    483483    // build the template fpa, set up the basic view
    484     fpa = pmFPAConstruct(config->camera);
     484    fpa = pmFPAConstruct(config->camera, config->cameraName);
    485485    if (!fpa) {
    486486        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", realName);
     
    783783
    784784    // build the template fpa, set up the basic view
    785     fpa = pmFPAConstruct (config->camera);
     785    fpa = pmFPAConstruct(config->camera, config->cameraName);
    786786    if (!fpa) {
    787787        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", (char *)infiles->data[0]);
     
    867867
    868868    // build the template fpa, set up the basic view
    869     pmFPA *fpa = pmFPAConstruct (config->camera);
     869    pmFPA *fpa = pmFPAConstruct(config->camera, config->cameraName);
    870870    if (!fpa) {
    871871        psError(PS_ERR_IO, false, "Failed to construct FPA for %s", filename);
     
    949949    if (!file) {
    950950        // build the template fpa, set up the basic view
    951         fpa = pmFPAConstruct (config->camera);
     951        fpa = pmFPAConstruct(config->camera, config->cameraName);
    952952        if (!fpa) {
    953953            psError(PS_ERR_IO, false, "Failed to construct FPA for %s", filename);
     
    10901090    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
    10911091
    1092     pmFPA *fpa = pmFPAConstruct(src->camera);
     1092    pmFPA *fpa = pmFPAConstruct(src->camera, psMetadataLookupStr(NULL, src->concepts, "FPA.CAMERA"));
    10931093    // XXX should this use DefineOutputForFormat?
    10941094    pmFPAfile *file = pmFPAfileDefineOutput (config, fpa, filename);
     
    11391139        return NULL;
    11401140    }
    1141     file->fpa = pmFPAConstruct(file->camera);
     1141    file->fpa = pmFPAConstruct(file->camera, file->cameraName);
    11421142
    11431143    return file;
  • trunk/psModules/src/camera/pmFPAfileFitsIO.c

    r16841 r17911  
    6767    }
    6868
    69     pmFPA *nameSource = file->src; // Source of FPA.NAME
     69    pmFPA *nameSource = file->src; // Source of FPA.OBS
    7070    if (!nameSource) {
    7171        nameSource = file->fpa;
    7272    }
    7373    bool mdok;                  // Status of MD lookup
    74     const char *fpaname = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.NAME"); // Name of FPA
    75 
    76     pmFPA *copy = pmFPAConstruct(file->camera);  // FPA to return
    77     if (!pmFPAAddSourceFromView(copy, fpaname, phuView, file->format)) {
     74    const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Observation id
     75
     76    pmFPA *copy = pmFPAConstruct(file->camera, file->cameraName);  // FPA to return
     77    if (!pmFPAAddSourceFromView(copy, fpaObs, phuView, file->format)) {
    7878        psError(PS_ERR_UNKNOWN, false, "Unable to insert HDU into FPA for writing.\n");
    7979        psFree(copy);
  • trunk/psModules/src/camera/pmFPAfileIO.c

    r17832 r17911  
    263263            }
    264264
    265             pmFPA *nameSource = file->src; // Source of FPA.NAME
     265            pmFPA *nameSource = file->src; // Source of FPA.OBS
    266266            if (!nameSource) {
    267267                nameSource = file->fpa;
    268268            }
    269269            bool mdok;                  // Status of MD lookup
    270             const char *fpaname = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.NAME"); // Name of FPA
    271 
    272             pmFPAAddSourceFromView(file->fpa, fpaname, view, format);
    273             psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n", file->name, file->name, view->chip, view->cell, view->readout);
     270            const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id
     271
     272            pmFPAAddSourceFromView(file->fpa, fpaObs, view, format);
     273            psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n",
     274                     file->name, file->name, view->chip, view->cell, view->readout);
    274275            break;
    275276    }
     
    349350    // (existing) fpa
    350351    if (file->type == PM_FPA_FILE_CMF) {
    351         if (!pmFPAviewCheckDataStatusForSources (view, file)) {
     352        if (!pmFPAviewCheckDataStatusForSources (view, file)) {
    352353        psTrace("psModules.camera", 6, "skip write for %s, no data for this entry", file->name);
    353354        return true;
     
    778779        file->fits->options = psMemIncrRefCounter(file->options);
    779780
    780         // in most cases, we have already open and read the phu and determined the format.
    781         // in some cases, (eg DetDB images), we have only just determined the filename.
    782         // we need to check the file format before we can work with the file
    783         if (!file->format) {
    784           psMetadata *phu = psFitsReadHeader (NULL, file->fits);
    785           if (!phu) {
    786             psError(PS_ERR_IO, false, "Failed to read file header %s\n", file->filename);
    787             return false;
    788           }
    789 
    790           // determine the current format from the header
    791           // determine camera if not specified already
    792           file->format = pmConfigCameraFormatFromHeader (config, phu, true);
    793           if (!file->format) {
    794             psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
    795             psFree(phu);
    796             return false;
    797           }
    798           psFree(phu);
    799         }
    800 
    801         // if needed, set the optional EXTWORD field based on the camera value
    802         psMetadata *fileMenu = psMetadataLookupMetadata (NULL, file->format, "FILE");
    803         if (!fileMenu) {
    804           psError (PS_ERR_IO, true, "FILE METADATA missing from camera format %s\n",
    805                    config->formatName);
    806           return false;
    807         }
    808         char *extword = psMetadataLookupStr (&status, fileMenu, "EXTWORD");
    809         if (status) {
    810           psFitsSetExtnameWord (file->fits, extword);
    811         }
     781        // in most cases, we have already open and read the phu and determined the format.
     782        // in some cases, (eg DetDB images), we have only just determined the filename.
     783        // we need to check the file format before we can work with the file
     784        if (!file->format) {
     785          psMetadata *phu = psFitsReadHeader (NULL, file->fits);
     786          if (!phu) {
     787            psError(PS_ERR_IO, false, "Failed to read file header %s\n", file->filename);
     788            return false;
     789          }
     790
     791          // determine the current format from the header
     792          // determine camera if not specified already
     793          file->format = pmConfigCameraFormatFromHeader (config, phu, true);
     794          if (!file->format) {
     795            psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
     796            psFree(phu);
     797            return false;
     798          }
     799          psFree(phu);
     800        }
     801
     802        // if needed, set the optional EXTWORD field based on the camera value
     803        psMetadata *fileMenu = psMetadataLookupMetadata (NULL, file->format, "FILE");
     804        if (!fileMenu) {
     805          psError (PS_ERR_IO, true, "FILE METADATA missing from camera format %s\n",
     806                   config->formatName);
     807          return false;
     808        }
     809        char *extword = psMetadataLookupStr (&status, fileMenu, "EXTWORD");
     810        if (status) {
     811          psFitsSetExtnameWord (file->fits, extword);
     812        }
    812813
    813814        // XXX these are probably only needed for WRITE files
  • trunk/psModules/src/concepts/pmConcepts.c

    r17874 r17911  
    462462}
    463463
     464// Register a concept
     465#define CONCEPT_REGISTER_FUNCTION(TYPENAME, SUFFIX, DEFAULT) \
     466static void conceptRegister##SUFFIX(const char *name, /* Name of concept */ \
     467                                    const char *comment, /* Comment for concept */ \
     468                                    pmConceptParseFunc parse, /* Parsing function */ \
     469                                    pmConceptFormatFunc format, /* Formatting function */ \
     470                                    bool required, /* Required concept? */ \
     471                                    pmFPALevel level /* Level at which concept applies */ \
     472    ) \
     473{ \
     474    psMetadataItem *item = psMetadataItemAlloc##TYPENAME(name, comment, DEFAULT); /* Item to add */ \
     475    pmConceptRegister(item, parse, format, required, level); \
     476    psFree(item); \
     477    return; \
     478}
     479
     480CONCEPT_REGISTER_FUNCTION(Str, Str, "");
     481CONCEPT_REGISTER_FUNCTION(F32, F32, NAN);
     482CONCEPT_REGISTER_FUNCTION(F64, F64, NAN);
     483CONCEPT_REGISTER_FUNCTION(S32, Enum, -1); // For enums: set default to -1
     484CONCEPT_REGISTER_FUNCTION(S32, S32, 0); // For values: set default to 0
     485
     486static void conceptRegisterTime(const char *name, /* Name of concept */ \
     487                                const char *comment, /* Comment for concept */ \
     488                                bool required, /* Required concept? */ \
     489                                pmFPALevel level /* Level at which concept applies */ \
     490    )
     491{
     492    psTime *time = psTimeAlloc(PS_TIME_TAI); // Blank time
     493    // Not particularly distinguishing, but should be good enough
     494    time->sec = 0;
     495    time->nsec = 0;
     496    psMetadataItem *item = psMetadataItemAlloc(name, PS_DATA_TIME, comment, time);
     497    psFree(time);
     498    pmConceptRegister(item, (pmConceptParseFunc)p_pmConceptParse_TIME,
     499                      (pmConceptFormatFunc)p_pmConceptFormat_TIME, required, level);
     500    psFree(item);
     501}
    464502
    465503bool pmConceptsInit(void)
     
    470508
    471509    bool init = false;                  // Did we initialise anything?
     510
    472511    if (! conceptsFPA) {
    473512        conceptsFPA = psMetadataAlloc();
     
    475514
    476515        // Install the standard concepts
    477 
    478         // FPA.TELESCOPE
    479         {
    480             psMetadataItem *fpaTelescope = psMetadataItemAllocStr("FPA.TELESCOPE", "Camera used", "");
    481             pmConceptRegister(fpaTelescope, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    482             psFree(fpaTelescope);
    483         }
    484 
    485         // FPA.INSTRUMENT
    486         {
    487             psMetadataItem *fpaInstrument = psMetadataItemAllocStr("FPA.INSTRUMENT", "Camera used", "");
    488             pmConceptRegister(fpaInstrument, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    489             psFree(fpaInstrument);
    490         }
    491 
    492         // FPA.DETECTOR
    493         {
    494             psMetadataItem *fpaDetector = psMetadataItemAllocStr("FPA.DETECTOR", "Detector used", "");
    495             pmConceptRegister(fpaDetector, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    496             psFree(fpaDetector);
    497         }
    498 
    499         // FPA.CAMERA
    500         // XXX keep or deprecate?
    501         {
    502             psMetadataItem *fpaCamera = psMetadataItemAllocStr("FPA.CAMERA", "Camera used", "");
    503             pmConceptRegister(fpaCamera, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    504             psFree(fpaCamera);
    505         }
    506 
    507         // FPA.COMMENT
    508         {
    509             psMetadataItem *item = psMetadataItemAllocStr("FPA.COMMENT", "Obs Comment", "");
    510             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    511             psFree(item);
    512         }
    513 
    514         // FPA.FOCUS
    515         {
    516             psMetadataItem *fpaFocus = psMetadataItemAllocF32("FPA.FOCUS", "Telescope focus", NAN);
    517             pmConceptRegister(fpaFocus, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    518             psFree(fpaFocus);
    519         }
    520 
    521         // FPA.AIRMASS
    522         {
    523             psMetadataItem *fpaAirmass = psMetadataItemAllocF32("FPA.AIRMASS", "Airmass at boresight", NAN);
    524             pmConceptRegister(fpaAirmass, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    525             psFree(fpaAirmass);
    526         }
    527 
    528         // FPA.FILTERID
    529         {
    530             psMetadataItem *fpaFilterid = psMetadataItemAllocStr("FPA.FILTERID",
    531                                                                  "Filter used (parsed, abstract name) ", "");
    532             pmConceptRegister(fpaFilterid, (pmConceptParseFunc)p_pmConceptParse_FPA_FILTER,
    533                               (pmConceptFormatFunc)p_pmConceptFormat_FPA_FILTER, false, PM_FPA_LEVEL_FPA);
    534             psFree(fpaFilterid);
    535         }
    536 
    537         // FPA.FILTER
    538         {
    539             psMetadataItem *fpaFilter = psMetadataItemAllocStr("FPA.FILTER", "Filter used", "");
    540             pmConceptRegister(fpaFilter, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    541             psFree(fpaFilter);
    542         }
    543 
    544         // FPA.POSANGLE
    545         {
    546             psMetadataItem *fpaPosangle = psMetadataItemAllocF32("FPA.POSANGLE",
    547                                           "Position angle of instrument", NAN);
    548             pmConceptRegister(fpaPosangle, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    549             psFree(fpaPosangle);
    550         }
    551 
    552         // FPA.RADECSYS
    553         {
    554             psMetadataItem *fpaRadecsys = psMetadataItemAllocStr("FPA.RADECSYS",
    555                                           "Celestial coordinate system", "");
    556             pmConceptRegister(fpaRadecsys, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    557             psFree(fpaRadecsys);
    558         }
    559 
    560         // FPA.RA
    561         {
    562             psMetadataItem *fpaRa = psMetadataItemAllocF64("FPA.RA", "Right Ascension of boresight", NAN);
    563             pmConceptRegister(fpaRa, (pmConceptParseFunc)p_pmConceptParse_FPA_Coords,
    564                               (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
    565             psFree(fpaRa);
    566         }
    567 
    568         // FPA.DEC
    569         {
    570             psMetadataItem *fpaDec = psMetadataItemAllocF64("FPA.DEC", "Declination of boresight", NAN);
    571             pmConceptRegister(fpaDec, (pmConceptParseFunc)p_pmConceptParse_FPA_Coords,
    572                               (pmConceptFormatFunc)p_pmConceptFormat_FPA_Coords, false, PM_FPA_LEVEL_FPA);
    573             psFree(fpaDec);
    574         }
    575 
    576         // FPA.OBSTYPE
    577         {
    578             psMetadataItem *fpaObstype = psMetadataItemAllocStr("FPA.OBSTYPE", "Type of observation", "");
    579             pmConceptRegister(fpaObstype, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    580             psFree(fpaObstype);
    581         }
    582 
    583         // FPA.OBJECT
    584         {
    585             psMetadataItem *fpaObject = psMetadataItemAllocStr("FPA.OBJECT", "Object of observation", "");
    586             pmConceptRegister(fpaObject, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    587             psFree(fpaObject);
    588         }
    589 
    590         // FPA.ALT
    591         {
    592             psMetadataItem *fpaAlt = psMetadataItemAllocF64("FPA.ALT", "Altitude of telescope", NAN);
    593             pmConceptRegister(fpaAlt, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    594             psFree(fpaAlt);
    595         }
    596 
    597         // FPA.AZ
    598         {
    599             psMetadataItem *fpaAz = psMetadataItemAllocF64("FPA.AZ", "Azimuth of telescope", NAN);
    600             pmConceptRegister(fpaAz, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    601             psFree(fpaAz);
    602         }
    603 
    604         // FPA.TIMESYS
    605         {
    606             psMetadataItem *fpaTimesys = psMetadataItemAllocS32("FPA.TIMESYS", "Time system", -1);
    607             pmConceptRegister(fpaTimesys, (pmConceptParseFunc)p_pmConceptParse_TIMESYS,
    608                               (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_FPA);
    609             psFree(fpaTimesys);
    610         }
    611 
    612         // FPA.TIME
    613         {
    614             psTime *time = psTimeAlloc(PS_TIME_TAI); // Blank time
    615             // Not particularly distinguishing, but should be good enough
    616             time->sec = 0;
    617             time->nsec = 0;
    618             psMetadataItem *fpaTime = psMetadataItemAlloc("FPA.TIME", PS_DATA_TIME,
    619                                       "Time of exposure", time);
    620             psFree(time);
    621             pmConceptRegister(fpaTime, (pmConceptParseFunc)p_pmConceptParse_TIME,
    622                               (pmConceptFormatFunc)p_pmConceptFormat_TIME, false, PM_FPA_LEVEL_FPA);
    623             psFree(fpaTime);
    624         }
    625 
    626         // FPA.TEMP
    627         {
    628             psMetadataItem *fpaTemp = psMetadataItemAllocF32("FPA.TEMP", "Temperature of focal plane", NAN);
    629             pmConceptRegister(fpaTemp, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    630             psFree(fpaTemp);
    631         }
    632 
    633         // FPA.M1X,Y,Z,TIP,TILT
    634         {
    635             psMetadataItem *item = psMetadataItemAllocF32("FPA.M1X", "Primary Mirror X Position", NAN);
    636             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    637             psFree(item);
    638         }
    639         {
    640             psMetadataItem *item = psMetadataItemAllocF32("FPA.M1Y", "Primary Mirror Y Position", NAN);
    641             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    642             psFree(item);
    643         }
    644         {
    645             psMetadataItem *item = psMetadataItemAllocF32("FPA.M1Z", "Primary Mirror Z Position", NAN);
    646             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    647             psFree(item);
    648         }
    649         {
    650             psMetadataItem *item = psMetadataItemAllocF32("FPA.M1TIP", "Primary Mirror TIP", NAN);
    651             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    652             psFree(item);
    653         }
    654         {
    655             psMetadataItem *item = psMetadataItemAllocF32("FPA.M1TILT", "Primary Mirror TILT", NAN);
    656             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    657             psFree(item);
    658         }
    659 
    660         // FPA.M2X,Y,Z,TIP,TILT
    661         {
    662             psMetadataItem *item = psMetadataItemAllocF32("FPA.M2X", "Primary Mirror X Position", NAN);
    663             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    664             psFree(item);
    665         }
    666         {
    667             psMetadataItem *item = psMetadataItemAllocF32("FPA.M2Y", "Primary Mirror Y Position", NAN);
    668             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    669             psFree(item);
    670         }
    671         {
    672             psMetadataItem *item = psMetadataItemAllocF32("FPA.M2Z", "Primary Mirror Z Position", NAN);
    673             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    674             psFree(item);
    675         }
    676         {
    677             psMetadataItem *item = psMetadataItemAllocF32("FPA.M2TIP", "Primary Mirror TIP", NAN);
    678             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    679             psFree(item);
    680         }
    681         {
    682             psMetadataItem *item = psMetadataItemAllocF32("FPA.M2TILT", "Primary Mirror TILT", NAN);
    683             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    684             psFree(item);
    685         }
    686 
    687         // FPA.ENV.*
    688         {
    689             psMetadataItem *item = psMetadataItemAllocF32("FPA.ENV.TEMP", "Environment: Temperature", NAN);
    690             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    691             psFree(item);
    692         }
    693         {
    694             psMetadataItem *item = psMetadataItemAllocF32("FPA.ENV.HUMID", "Environment: Humidity", NAN);
    695             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    696             psFree(item);
    697         }
    698         {
    699             psMetadataItem *item = psMetadataItemAllocF32("FPA.ENV.WIND", "Environment: Wind Speed", NAN);
    700             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    701             psFree(item);
    702         }
    703         {
    704             psMetadataItem *item = psMetadataItemAllocF32("FPA.ENV.DIR", "Environment: Wind Direction", NAN);
    705             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    706             psFree(item);
    707         }
    708 
    709         // FPA.TELTEMP.*
    710         {
    711             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.M1", "Telescope Temperatures: M1", NAN);
    712             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    713             psFree(item);
    714         }
    715         {
    716             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.M1CELL", "Telescope Temperatures: M1 CELL", NAN);
    717             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    718             psFree(item);
    719         }
    720         {
    721             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.M2", "Telescope Temperatures: M2", NAN);
    722             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    723             psFree(item);
    724         }
    725         {
    726             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.SPIDER", "Telescope Temperatures: SPIDER", NAN);
    727             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    728             psFree(item);
    729         }
    730         {
    731             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.TRUSS", "Telescope Temperatures: TRUSS", NAN);
    732             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    733             psFree(item);
    734         }
    735         {
    736             psMetadataItem *item = psMetadataItemAllocF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: EXTRA", NAN);
    737             pmConceptRegister(item, p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
    738             psFree(item);
    739         }
    740 
    741         // FPA.PON.TIME
    742         {
    743             psMetadataItem *item = psMetadataItemAllocF32("FPA.PON.TIME", "Power On Time", NAN);
    744             pmConceptRegister(item, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    745             psFree(item);
    746         }
    747 
    748         // FPA.EXPOSURE
    749         {
    750             psMetadataItem *fpaExposure = psMetadataItemAllocF32("FPA.EXPOSURE",
    751                                           "Exposure time (sec)", NAN);
    752             pmConceptRegister(fpaExposure, NULL, NULL, false, PM_FPA_LEVEL_FPA);
    753             psFree(fpaExposure);
    754         }
    755 
    756         // Done with FPA level concepts
     516        conceptRegisterStr("FPA.TELESCOPE", "Telescope of origin", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     517        conceptRegisterStr("FPA.INSTRUMENT", "Instrument name (according to the instrument)",
     518                           NULL, NULL, false, PM_FPA_LEVEL_FPA);
     519        conceptRegisterStr("FPA.DETECTOR", "Detector name", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     520        conceptRegisterStr("FPA.COMMENT", "Observation comment", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     521        conceptRegisterF32("FPA.FOCUS", "Telescope focus", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     522        conceptRegisterF32("FPA.AIRMASS", "Airmass at boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     523        conceptRegisterStr("FPA.FILTERID", "Filter used (parsed, abstract name)",
     524                           NULL, NULL, false, PM_FPA_LEVEL_FPA);
     525        conceptRegisterStr("FPA.FILTER", "Filter used (instrument name)",
     526                           NULL, NULL, false, PM_FPA_LEVEL_FPA);
     527        conceptRegisterF32("FPA.POSANGLE", "Position angle of instrument",
     528                           NULL, NULL, false, PM_FPA_LEVEL_FPA);
     529        conceptRegisterStr("FPA.RADECSYS", "Celestial coordinate system",
     530                           NULL, NULL, false, PM_FPA_LEVEL_FPA);
     531        conceptRegisterF64("FPA.RA", "Right Ascension of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     532        conceptRegisterF64("FPA.DEC", "Declination of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     533        conceptRegisterStr("FPA.OBSTYPE", "Type of observation", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     534        conceptRegisterStr("FPA.OBJECT", "Object of observation", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     535        conceptRegisterF64("FPA.ALT", "Altitude of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     536        conceptRegisterF64("FPA.AZ", "Azimuth of boresight", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     537        conceptRegisterEnum("FPA.TIMESYS", "Time system", p_pmConceptParse_TIMESYS,
     538                            p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_FPA);
     539        conceptRegisterF32("FPA.TEMP", "Temperature of focal plane", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     540        conceptRegisterF32("FPA.M1X", "Primary Mirror X Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     541        conceptRegisterF32("FPA.M1Y", "Primary Mirror Y Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     542        conceptRegisterF32("FPA.M1Z", "Primary Mirror Z Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     543        conceptRegisterF32("FPA.M1TIP", "Primary Mirror TIP", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     544        conceptRegisterF32("FPA.M1TILT", "Primary Mirror TILT", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     545        conceptRegisterF32("FPA.M2X", "Primary Mirror X Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     546        conceptRegisterF32("FPA.M2Y", "Primary Mirror Y Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     547        conceptRegisterF32("FPA.M2Z", "Primary Mirror Z Position", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     548        conceptRegisterF32("FPA.M2TIP", "Primary Mirror TIP", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     549        conceptRegisterF32("FPA.M2TILT", "Primary Mirror TILT", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     550        conceptRegisterF32("FPA.ENV.TEMP", "Environment: Temperature", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     551        conceptRegisterF32("FPA.ENV.HUMID", "Environment: Humidity", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     552        conceptRegisterF32("FPA.ENV.WIND", "Environment: Wind speed", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     553        conceptRegisterF32("FPA.ENV.DIR", "Environment: Wind direction", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     554        conceptRegisterF32("FPA.TELTEMP.M1", "Telescope Temperatures: M1",
     555                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     556        conceptRegisterF32("FPA.TELTEMP.M1CELL", "Telescope Temperatures: M1 cell",
     557                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     558        conceptRegisterF32("FPA.TELTEMP.M2", "Telescope Temperatures: M2",
     559                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     560        conceptRegisterF32("FPA.TELTEMP.SPIDER", "Telescope Temperatures: spider",
     561                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     562        conceptRegisterF32("FPA.TELTEMP.TRUSS", "Telescope Temperatures: truss",
     563                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     564        conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra",
     565                           p_pmConceptParse_TELTEMPS, NULL, false, PM_FPA_LEVEL_FPA);
     566        conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     567        conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, false, PM_FPA_LEVEL_FPA);
     568        conceptRegisterTime("FPA.TIME", "Time of exposure", false, PM_FPA_LEVEL_FPA);
    757569    }
    758570    if (! conceptsChip) {
     
    761573
    762574        // Install the standard concepts
    763 
    764         // CHIP.XPARITY
    765         {
    766             psMetadataItem *chipXparity = psMetadataItemAllocS32("CHIP.XPARITY",
    767                                           "Orientation in x compared to the rest of the FPA", 0);
    768             pmConceptRegister(chipXparity, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
    769             psFree(chipXparity);
    770         }
    771 
    772         // CHIP.YPARITY
    773         {
    774             psMetadataItem *chipYparity = psMetadataItemAllocS32("CHIP.YPARITY",
    775                                           "Orientation in y compared to the rest of the FPA", 0);
    776             pmConceptRegister(chipYparity, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
    777             psFree(chipYparity);
    778         }
    779 
    780         // CHIP.X0
    781         {
    782             psMetadataItem *chipX0 = psMetadataItemAllocS32("CHIP.X0", "Position of (0,0) on the FPA", 0);
    783             pmConceptRegister(chipX0, (pmConceptParseFunc)p_pmConceptParse_Positions,
    784                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
    785             psFree(chipX0);
    786         }
    787 
    788         // CHIP.Y0
    789         {
    790             psMetadataItem *chipY0 = psMetadataItemAllocS32("CHIP.Y0", "Position of (0,0) on the FPA", 0);
    791             pmConceptRegister(chipY0, (pmConceptParseFunc)p_pmConceptParse_Positions,
    792                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
    793             psFree(chipY0);
    794         }
    795 
    796         // CHIP.XSIZE
    797         {
    798             psMetadataItem *chipXsize = psMetadataItemAllocS32("CHIP.XSIZE", "Size of chip (pixels)", 0);
    799             pmConceptRegister(chipXsize, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
    800             psFree(chipXsize);
    801         }
    802 
    803         // CHIP.YSIZE
    804         {
    805             psMetadataItem *chipYsize = psMetadataItemAllocS32("CHIP.YSIZE", "Size of chip (pixels)", 0);
    806             pmConceptRegister(chipYsize, NULL, NULL, true, PM_FPA_LEVEL_CHIP);
    807             psFree(chipYsize);
    808         }
    809 
    810         // CHIP.TEMP
    811         {
    812             psMetadataItem *chipTemp = psMetadataItemAllocF32("CHIP.TEMP", "Temperature of chip", NAN);
    813             pmConceptRegister(chipTemp, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
    814             psFree(chipTemp);
    815         }
    816 
    817         // CHIP.ID
    818         {
    819             psMetadataItem *chipID = psMetadataItemAllocStr("CHIP.ID", "Chip identifier", "");
    820             pmConceptRegister(chipID, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
    821             psFree(chipID);
    822         }
    823 
    824         // Done with chip level concepts
    825     }
     575        conceptRegisterS32("CHIP.XPARITY", "Orientation in x compared to the rest of the FPA",
     576                           NULL, NULL, true, PM_FPA_LEVEL_CHIP);
     577
     578        conceptRegisterS32("CHIP.YPARITY", "Orientation in y compared to the rest of the FPA",
     579                           NULL, NULL, true, PM_FPA_LEVEL_CHIP);
     580        conceptRegisterS32("CHIP.X0", "Position of (0,0) on the FPA",
     581                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     582                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
     583        conceptRegisterS32("CHIP.Y0", "Position of (0,0) on the FPA",
     584                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     585                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CHIP);
     586        conceptRegisterS32("CHIP.XSIZE", "Size of chip (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
     587        conceptRegisterS32("CHIP.YSIZE", "Size of chip (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CHIP);
     588        conceptRegisterF32("CHIP.TEMP", "Temperature of chip", NULL, NULL, false, PM_FPA_LEVEL_CHIP);
     589        conceptRegisterStr("CHIP.ID", "Chip identifier", NULL, NULL, false, PM_FPA_LEVEL_CHIP);
     590    }
     591
    826592    if (! conceptsCell) {
    827593        conceptsCell = psMetadataAlloc();
     
    829595
    830596        // Install the standard concepts
    831 
    832         // CELL.GAIN
    833         {
    834             psMetadataItem *cellGain = psMetadataItemAllocF32("CELL.GAIN", "CCD gain (e/count)", NAN);
    835             pmConceptRegister(cellGain, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    836             psFree(cellGain);
    837         }
    838 
    839         // CELL.READNOISE
    840         {
    841             psMetadataItem *cellReadnoise = psMetadataItemAllocF32("CELL.READNOISE",
    842                                             "CCD read noise (e)", NAN);
    843             pmConceptRegister(cellReadnoise, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    844             psFree(cellReadnoise);
    845         }
    846 
    847         // CELL.SATURATION
    848         {
    849             psMetadataItem *cellSaturation = psMetadataItemAllocF32("CELL.SATURATION",
    850                                              "Saturation level (counts)", NAN);
    851             pmConceptRegister(cellSaturation, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    852             psFree(cellSaturation);
    853         }
    854 
    855         // CELL.BAD
    856         {
    857             psMetadataItem *cellBad = psMetadataItemAllocF32("CELL.BAD", "Bad level (counts)", NAN);
    858             pmConceptRegister(cellBad, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    859             psFree(cellBad);
    860         }
    861 
    862         // CELL.XPARITY
    863         {
    864             psMetadataItem *cellXparity = psMetadataItemAllocS32("CELL.XPARITY",
    865                                           "Orientation in x compared to the rest of the chip", 0);
    866             pmConceptRegister(cellXparity, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    867             psFree(cellXparity);
    868         }
    869 
    870         // CELL.YPARITY
    871         {
    872             psMetadataItem *cellYparity = psMetadataItemAllocS32("CELL.YPARITY",
    873                                           "Orientation in y compared to the rest of the chip", 0);
    874             pmConceptRegister(cellYparity, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    875             psFree(cellYparity);
    876         }
    877 
    878         // CELL.READDIR
    879         {
    880             psMetadataItem *cellReaddir = psMetadataItemAllocS32("CELL.READDIR",
    881                                           "Read direction, rows=1, cols=2", 0);
    882             pmConceptRegister(cellReaddir, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    883             psFree(cellReaddir);
    884         }
    885 
     597        conceptRegisterF32("CELL.GAIN", "CCD gain (e/count)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
     598        conceptRegisterF32("CELL.READNOISE", "CCD read noise (e)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
     599        conceptRegisterF32("CELL.SATURATION", "Saturation level (counts)",
     600                           NULL, NULL, true, PM_FPA_LEVEL_CELL);
     601        conceptRegisterF32("CELL.BAD", "Bad level (counts)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
     602        conceptRegisterS32("CELL.XPARITY", "Orientation in x compared to the rest of the chip",
     603                           NULL, NULL, true, PM_FPA_LEVEL_CELL);
     604        conceptRegisterS32("CELL.YPARITY", "Orientation in y compared to the rest of the chip",
     605                           NULL, NULL, true, PM_FPA_LEVEL_CELL);
     606        conceptRegisterS32("CELL.READDIR", "Read direction, rows=1, cols=2",
     607                           NULL, NULL, true, PM_FPA_LEVEL_CELL);
    886608
    887609        // These (CELL.EXPOSURE and CELL.DARKTIME) used to be READOUT.EXPOSURE and READOUT.DARKTIME, but that
     
    890612        // readout is a plane in a 3D image.  We'll have to dream up some additional suffix to specify these,
    891613        // but for now....
    892 
    893         // CELL.EXPOSURE
    894         {
    895             psMetadataItem *cellExposure = psMetadataItemAllocF32("CELL.EXPOSURE",
    896                                            "Exposure time (sec)", NAN);
    897             pmConceptRegister(cellExposure, NULL, NULL, false, PM_FPA_LEVEL_CELL);
    898             psFree(cellExposure);
    899         }
    900 
    901         // CELL.DARKTIME
    902         {
    903             psMetadataItem *cellDarktime = psMetadataItemAllocF32("CELL.DARKTIME",
    904                                            "Time since flush (sec)", NAN);
    905             pmConceptRegister(cellDarktime, NULL, NULL, false, PM_FPA_LEVEL_CELL);
    906             psFree(cellDarktime);
    907         }
     614        conceptRegisterF32("CELL.EXPOSURE", "Exposure time (sec)", NULL, NULL, false, PM_FPA_LEVEL_CELL);
     615        conceptRegisterF32("CELL.DARKTIME", "Time since flush (sec)", NULL, NULL, false, PM_FPA_LEVEL_CELL);
     616
     617        conceptRegisterS32("CELL.XBIN", "Binning in x", (pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
     618                           (pmConceptFormatFunc)p_pmConceptFormat_CELL_XBIN, true, PM_FPA_LEVEL_CELL);
     619        conceptRegisterS32("CELL.YBIN", "Binning in y",(pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
     620                           (pmConceptFormatFunc)p_pmConceptFormat_CELL_YBIN, true, PM_FPA_LEVEL_CELL);
     621        conceptRegisterEnum("CELL.TIMESYS", "Time system", (pmConceptParseFunc)p_pmConceptParse_TIMESYS,
     622                            (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_CELL);
     623        conceptRegisterTime("CELL.TIME", "Time of exposure", false, PM_FPA_LEVEL_CELL);
     624        conceptRegisterS32("CELL.X0", "Position of (0,0) on the chip",
     625                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     626                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
     627        conceptRegisterS32("CELL.Y0", "Position of (0,0) on the chip",
     628                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     629                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
     630        conceptRegisterS32("CELL.XSIZE", "Size of cell (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
     631        conceptRegisterS32("CELL.YSIZE", "Size of cell (pixels)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
     632        conceptRegisterS32("CELL.XWINDOW", "Start of cell window (pixels)",
     633                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     634                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
     635        conceptRegisterS32("CELL.YWINDOW", "Start of cell window (pixels)",
     636                           (pmConceptParseFunc)p_pmConceptParse_Positions,
     637                           (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
    908638
    909639        // CELL.TRIMSEC
     
    930660        }
    931661
    932         // CELL.XBIN
    933         {
    934             psMetadataItem *cellXbin = psMetadataItemAllocS32("CELL.XBIN", "Binning in x", 0);
    935             pmConceptRegister(cellXbin, (pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
    936                               (pmConceptFormatFunc)p_pmConceptFormat_CELL_XBIN, true, PM_FPA_LEVEL_CELL);
    937             psFree(cellXbin);
    938         }
    939 
    940         // CELL.YBIN
    941         {
    942             psMetadataItem *cellYbin = psMetadataItemAllocS32("CELL.YBIN", "Binning in y", 0);
    943             pmConceptRegister(cellYbin, (pmConceptParseFunc)p_pmConceptParse_CELL_Binning,
    944                               (pmConceptFormatFunc)p_pmConceptFormat_CELL_YBIN, true, PM_FPA_LEVEL_CELL);
    945             psFree(cellYbin);
    946         }
    947 
    948         // CELL.TIMESYS
    949         {
    950             psMetadataItem *cellTimesys = psMetadataItemAllocS32("CELL.TIMESYS", "Time system", -1);
    951             pmConceptRegister(cellTimesys, (pmConceptParseFunc)p_pmConceptParse_TIMESYS,
    952                               (pmConceptFormatFunc)p_pmConceptFormat_TIMESYS, false, PM_FPA_LEVEL_CELL);
    953             psFree(cellTimesys);
    954         }
    955 
    956         // CELL.TIME
    957         {
    958             psTime *time = psTimeAlloc(PS_TIME_TAI); // Blank time
    959             // Not particularly distinguishing, but should be good enough
    960             time->sec = 0;
    961             time->nsec = 0;
    962             psMetadataItem *cellTime = psMetadataItemAlloc("CELL.TIME", PS_DATA_TIME,
    963                                        "Time of exposure", time);
    964             psFree(time);
    965             pmConceptRegister(cellTime, (pmConceptParseFunc)p_pmConceptParse_TIME,
    966                               (pmConceptFormatFunc)p_pmConceptFormat_TIME, false, PM_FPA_LEVEL_CELL);
    967             psFree(cellTime);
    968         }
    969 
    970         // CELL.X0
    971         {
    972             psMetadataItem *cellX0 = psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", 0);
    973             pmConceptRegister(cellX0, (pmConceptParseFunc)p_pmConceptParse_Positions,
    974                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
    975             psFree(cellX0);
    976         }
    977 
    978         // CELL.Y0
    979         {
    980             psMetadataItem *cellY0 = psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", 0);
    981             pmConceptRegister(cellY0, (pmConceptParseFunc)p_pmConceptParse_Positions,
    982                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
    983             psFree(cellY0);
    984         }
    985 
    986         // CELL.XSIZE
    987         {
    988             psMetadataItem *cellXsize = psMetadataItemAllocS32("CELL.XSIZE", "Size of cell (pixels)", 0);
    989             pmConceptRegister(cellXsize, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    990             psFree(cellXsize);
    991         }
    992 
    993         // CELL.YSIZE
    994         {
    995             psMetadataItem *cellYsize = psMetadataItemAllocS32("CELL.YSIZE", "Size of cell (pixels)", 0);
    996             pmConceptRegister(cellYsize, NULL, NULL, true, PM_FPA_LEVEL_CELL);
    997             psFree(cellYsize);
    998         }
    999 
    1000         // CELL.XWINDOW
    1001         {
    1002             psMetadataItem *cellXwindow = psMetadataItemAllocS32("CELL.XWINDOW",
    1003                                                                  "Start of cell window (pixels)", 0);
    1004             pmConceptRegister(cellXwindow, (pmConceptParseFunc)p_pmConceptParse_Positions,
    1005                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
    1006             psFree(cellXwindow);
    1007         }
    1008 
    1009         // CELL.YWINDOW
    1010         {
    1011             psMetadataItem *cellYwindow = psMetadataItemAllocS32("CELL.YWINDOW",
    1012                                                                  "Start of cell window (pixels)", 0);
    1013             pmConceptRegister(cellYwindow, (pmConceptParseFunc)p_pmConceptParse_Positions,
    1014                               (pmConceptFormatFunc)p_pmConceptFormat_Positions, true, PM_FPA_LEVEL_CELL);
    1015             psFree(cellYwindow);
    1016         }
    1017662    }
    1018663
     
    1037682// List of concepts not to copy, for each level.
    1038683// Must be NULL-terminated
    1039 static const char *dontCopyConceptsFPA[] = { "FPA.NAME", 0 };
     684static const char *dontCopyConceptsFPA[] = { "FPA.NAME", "FPA.CAMERA", 0 };
    1040685static const char *dontCopyConceptsChip[] = { "CHIP.NAME", 0 };
    1041686static const char *dontCopyConceptsCell[] = { "CELL.NAME", "CELL.TRIMSEC", "CELL.BIASSEC", 0 };
     
    1202847// Interpolate the concept.  Generalises the FPA/Chip/Cell
    1203848#define CONCEPT_INTERPOLATE(SOURCE, NAME) \
    1204     if (strncmp(concept, NAME, 4) == 0) { \
     849    if (strncmp(concept, NAME, strlen(NAME)) == 0) { \
    1205850        if (!(SOURCE)) { \
    1206851            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot interpolate %s because %s not provided", \
     
    1274919    return string;
    1275920}
     921
     922
     923psMetadataItem *p_pmConceptsDepend(const char *name, const psMetadata *menu, const psMetadata *source,
     924                                   const pmFPA *fpa, const pmChip *chip, const pmCell *cell)
     925{
     926    psAssert(name && strlen(name) > 0, "Concept name is empty");
     927    psAssert(menu, "Must have menu");
     928    psAssert(source, "Must have source");
     929
     930    // Check for DEPEND
     931    psString depend = NULL; // The CONCEPT.DEPEND
     932    psStringAppend(&depend, "%s.DEPEND", name);
     933    bool mdok;                          // Status of MD lookup
     934    const char *dependConcept = psMetadataLookupStr(&mdok, source, depend); // The concept name
     935    if (!mdok || !dependConcept || strlen(dependConcept) == 0) {
     936        psError(PS_ERR_IO, true, "Unable to parse %s: couldn't find %s in DEFAULTS.\n", name, depend);
     937        psFree(depend);
     938        return NULL;
     939    }
     940    psFree(depend);
     941    // Now look up the depend value
     942    psMetadataItem *dependValue = NULL; // The value of the concept we're looking up
     943    if (cell) {
     944        dependValue = psMetadataLookup(cell->concepts, dependConcept);
     945    }
     946    if (chip && !dependValue) {
     947        dependValue = psMetadataLookup(chip->concepts, dependConcept);
     948    }
     949    if (fpa && !dependValue) {
     950        dependValue = psMetadataLookup(chip->concepts, dependConcept);
     951    }
     952    if (!dependValue) {
     953        // Not an error --- it may be specified some other way
     954        psTrace("psModules.concepts", 7, "Couldn't find DEPEND for %s", name);
     955        return NULL;
     956    }
     957    if (dependValue->type != PS_DATA_STRING) {
     958        psError(PS_ERR_BAD_PARAMETER_TYPE, true, "%s is required to resolve %s in DEFAULTS, "
     959                "but it is not of type STRING.\n", dependConcept, name);
     960        return NULL;
     961    }
     962    const char *key = dependValue->data.V; // The key to the DEPEND menu
     963    psTrace("psModules.concepts", 7, "%s.DEPEND resolves to %s....\n", name, key);
     964
     965    return psMetadataLookup(menu, key);
     966}
     967
  • trunk/psModules/src/concepts/pmConcepts.h

    r17864 r17911  
    44 * @author Paul Price, IfA
    55 *
    6  * @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
    7  * @date $Date: 2008-05-30 21:35:51 $
     6 * @version $Revision: 1.17 $ $Name: not supported by cvs2svn $
     7 * @date $Date: 2008-06-05 01:31:33 $
    88 * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
    99 */
     
    231231    );
    232232
     233/// Look up a dependency menu to get a concept's value
     234///
     235/// Returns a psMetadataItem with the concept value
     236psMetadataItem *p_pmConceptsDepend(const char *name, ///< Name of concept for which to get dependent value
     237                                   const psMetadata *menu, ///< Menu in which to look up key
     238                                   const psMetadata *source, ///< Source metadata with CONCEPT.DEPEND
     239                                   const pmFPA *fpa, ///< FPA for dependency
     240                                   const pmChip *chip, ///< Chip for dependency
     241                                   const pmCell *cell ///< Cell for dependency
     242    );
    233243
    234244/// @}
  • trunk/psModules/src/concepts/pmConceptsRead.c

    r17874 r17911  
    181181}
    182182
     183psMetadataItem *p_pmConceptsReadSingleFromDefaults(const char *name, const psMetadata *defaults,
     184                                                  const pmFPA *fpa, const pmChip *chip, const pmCell *cell)
     185{
     186    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
     187    PS_ASSERT_METADATA_NON_NULL(defaults, NULL);
     188
     189    psMetadataItem *item = psMetadataLookup(defaults, name); // The concept, or NULL
     190    psTrace("psModules.concepts", 10, "%s: %p\n", name, item);
     191    if (item && item->type == PS_DATA_METADATA) {
     192        // This is a menu
     193        psTrace("psModules.concepts", 5, "%s is of type METADATA.\n", name);
     194        item = p_pmConceptsDepend(name, item->data.md, defaults, fpa, chip, cell);
     195    }
     196    return item;
     197}
    183198
    184199bool p_pmConceptsReadFromDefaults(psMetadata *target, const psMetadata *specs,
     
    209224        pmConceptSpec *spec = specItem->data.V; // The specification
    210225        psString name = specItem->name; // The concept name
    211         psMetadataItem *conceptItem = psMetadataLookup(defaults, name); // The concept, or NULL
    212         psTrace("psModules.concepts", 10, "%s: %p\n", name, conceptItem);
    213         if (conceptItem && conceptItem->type == PS_DATA_METADATA) {
    214             psTrace("psModules.concepts", 5, "%s is of type METADATA.\n", name);
    215             // Check for DEPEND
    216             psMetadata *dependMenu = conceptItem->data.V; // The DEPEND menu
    217             psString depend = NULL; // The CONCEPT.DEPEND
    218             psStringAppend(&depend, "%s.DEPEND", name);
    219             const char *dependConcept = psMetadataLookupStr(&mdok, defaults, depend); // The concept name
    220             if (!mdok || !dependConcept || strlen(dependConcept) == 0) {
    221                 psError(PS_ERR_IO, true, "Unable to parse %s: couldn't find %s in DEFAULTS.\n", name,
    222                         depend);
    223                 psFree(depend);
    224                 continue;
    225             }
    226             psFree(depend);
    227             // Now look up the depend value
    228             psMetadataItem *dependValue = NULL; // The value of the concept we're looking up
    229             if (cell) {
    230                 dependValue = psMetadataLookup(cell->concepts, dependConcept);
    231             }
    232             if (chip && !dependValue) {
    233                 dependValue = psMetadataLookup(chip->concepts, dependConcept);
    234             }
    235             if (fpa && !dependValue) {
    236                 dependValue = psMetadataLookup(chip->concepts, dependConcept);
    237             }
    238             if (!dependValue) {
    239                 psError(PS_ERR_IO, true, "Unable to find %s to resolve %s in DEFAULTS.\n",
    240                         dependConcept, name);
    241                 continue;
    242             }
    243             if (dependValue->type != PS_DATA_STRING) {
    244                 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "%s is required to resolve %s in DEFAULTS, "
    245                         "but it is not of type STRING.\n", dependConcept, name);
    246                 continue;
    247             }
    248             const char *dependKey = dependValue->data.V; // The key to the DEPEND menu
    249             psTrace("psModules.concepts", 7, "%s.DEPEND resolves to %s....\n", name, dependKey);
    250 
    251             conceptItem = psMetadataLookup(dependMenu, dependKey);
    252             // Now we can parse this as we would ordinarily
    253         }
     226        psMetadataItem *conceptItem = p_pmConceptsReadSingleFromDefaults(name, defaults, fpa, chip, cell);
    254227        if (conceptItem && !conceptParse(spec, conceptItem, PM_CONCEPT_SOURCE_DEFAULTS,
    255228                                         cameraFormat, target, fpa, chip, cell)) {
     
    282255    psMetadata *cameraFormat = hduLow->format; // The camera format
    283256    bool mdok = true;                   // Status of MD lookup
    284     psMetadata *transSpec = psMetadataLookupMetadata(&mdok, cameraFormat, "TRANSLATION"); // The TRANSLATION spec
     257    psMetadata *transSpec = psMetadataLookupMetadata(&mdok, cameraFormat, "TRANSLATION"); // TRANSLATION spec
    285258    if (!mdok || !transSpec) {
    286259        psError(PS_ERR_IO, true, "Failed to find \"TRANSLATION\"");
     
    318291        }
    319292
    320         if (! headerItem) {
    321             psString keywords = psMetadataLookupStr(&mdok, transSpec, name); // The FITS keywords
    322             if (mdok && strlen(keywords) > 0) {
    323                 // In case there are multiple headers
    324                 psList *keys = psStringSplit(keywords, " ,;", true); // List of keywords
    325                 if (keys->n == 1) {
    326                     // Only one key --- proceed as usual
     293        if (!headerItem) {
     294            psMetadataItem *formatItem = psMetadataLookup(transSpec, name); // Item with keyword
     295            if (!formatItem) {
     296                continue;
     297            }
     298            if (formatItem->type == PS_DATA_METADATA) {
     299                // This is a menu
     300                psTrace("psModules.concepts", 5, "%s is of type METADATA.\n", name);
     301                formatItem = p_pmConceptsDepend(name, formatItem->data.md, transSpec, fpa, chip, cell);
     302                if (!formatItem) {
     303                    continue;
     304                }
     305            }
     306            if (formatItem->type != PS_DATA_STRING) {
     307                psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Type for concept %s in TRANSLATION is not STR",
     308                        name);
     309                psFree(specsIter);
     310                return false;
     311            }
     312            psString keywords = formatItem->data.str; // The FITS keywords
     313
     314            // In case there are multiple headers
     315            psList *keys = psStringSplit(keywords, " ,;", true); // List of keywords
     316            if (keys->n == 1) {
     317                // Only one key --- proceed as usual
     318                if (hduLow->header) {
     319                    headerItem = psMetadataLookup(hduLow->header, keywords);
     320                }
     321                if (!headerItem && hduHigh != hduLow && hduHigh->header) {
     322                    headerItem = psMetadataLookup(hduHigh->header, keywords);
     323                }
     324                psMemIncrRefCounter(headerItem);
     325            } else {
     326                psListIterator *keysIter = psListIteratorAlloc(keys, PS_LIST_HEAD, false); // Iterator
     327                psString key = NULL; // Item from iteration
     328                psList *values = psListAlloc(NULL); // List containing the values
     329                while ((key = psListGetAndIncrement(keysIter))) {
     330                    psMetadataItem *value = NULL;
    327331                    if (hduLow->header) {
    328                         headerItem = psMetadataLookup(hduLow->header, keywords);
    329                     }
    330                     if (!headerItem && hduHigh != hduLow && hduHigh->header) {
    331                         headerItem = psMetadataLookup(hduHigh->header, keywords);
    332                     }
    333                     psMemIncrRefCounter(headerItem);
    334                 } else {
    335                     psListIterator *keysIter = psListIteratorAlloc(keys, PS_LIST_HEAD, false); // Iterator
    336                     psString key = NULL; // Item from iteration
    337                     psList *values = psListAlloc(NULL); // List containing the values
    338                     while ((key = psListGetAndIncrement(keysIter))) {
    339                         psMetadataItem *value = NULL;
    340                         if (hduLow->header) {
    341                             value = psMetadataLookup(hduLow->header, key);
    342                         }
    343                         if (!value && hduHigh != hduLow && hduHigh->header) {
    344                             value = psMetadataLookup(hduHigh->header, key);
    345                         }
    346                         if (value) {
    347                             psListAdd(values, PS_LIST_TAIL, value);
    348                         } else {
    349                             psWarning("Unable to find header %s --- assuming value is NULL", key);
    350                         }
    351                     }
    352                     psFree(keysIter);
    353                     headerItem = psMetadataItemAlloc(name, PS_DATA_LIST, specItem->comment, values);
    354                     psFree(values);
    355                 }
    356                 psFree(keys);
    357             }
     332                        value = psMetadataLookup(hduLow->header, key);
     333                    }
     334                    if (!value && hduHigh != hduLow && hduHigh->header) {
     335                        value = psMetadataLookup(hduHigh->header, key);
     336                    }
     337                    if (value) {
     338                        psListAdd(values, PS_LIST_TAIL, value);
     339                    } else {
     340                        psWarning("Unable to find header %s --- assuming value is NULL", key);
     341                    }
     342                }
     343                psFree(keysIter);
     344                headerItem = psMetadataItemAlloc(name, PS_DATA_LIST, specItem->comment, values);
     345                psFree(values);
     346            }
     347            psFree(keys);
    358348        }
    359349
     
    371361    psFree(specsIter);
    372362    return status;
     363}
     364
     365psMetadataItem *p_pmConceptsReadSingleFromDatabase(const char *name, const psMetadata *database, psDB *db,
     366                                                   const pmFPA *fpa, const pmChip *chip, const pmCell *cell)
     367{
     368    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
     369    PS_ASSERT_METADATA_NON_NULL(database, NULL);
     370
     371    psMetadataItem *item = psMetadataLookup(database, name); // Item to return
     372    if (item && item->type == PS_DATA_METADATA) {
     373        // This is a menu
     374        psTrace("psModules.concepts", 5, "%s is of type METADATA.\n", name);
     375        item = p_pmConceptsDepend(name, item->data.md, database, fpa, chip, cell);
     376    }
     377    if (!item) {
     378        return NULL;
     379    }
     380    if (item->type != PS_DATA_STRING) {
     381        psWarning("%s in DATABASE in camera format is not of type STR --- ignored.", name);
     382        return NULL;
     383    }
     384
     385    psString sql = pmConceptsInterpolate(item->data.str, fpa, chip, cell);
     386    if (!p_psDBRunQuery(db, sql)) {
     387        psWarning("Unable to query database for concept %s --- ignored.", name);
     388        psFree(sql);
     389        return NULL;
     390    }
     391    psFree(sql);
     392
     393    psArray *rows = p_psDBFetchResult(db); // Rows returned from the query
     394    if (rows->n == 0) {
     395        psWarning("No rows returned from database query for concept %s --- ignored.", name);
     396        return NULL;
     397    }
     398    if (rows->n > 1) {
     399        psWarning("Multiple rows returned from database query for concept %s --- using the first", name);
     400    }
     401    psMetadata *row = rows->data[0]; // First (and only) row
     402    if (row->list->n > 1) {
     403        psWarning("Multiple columns returned from database query for concept %s --- using the first", name);
     404    }
     405
     406    return psMetadataGet(row, PS_LIST_HEAD); // Item of interest
    373407}
    374408
     
    400434        pmConceptSpec *spec = specItem->data.V; // The specification
    401435        psString name = specItem->name; // The concept name
    402         const char *dbLookup = psMetadataLookupStr(&mdok, dbSpec, name);
    403         if (mdok && dbLookup) {
    404             psString sql = pmConceptsInterpolate(dbLookup, fpa, chip, cell);
    405 
    406             if (!p_psDBRunQuery(db, sql)) {
    407                 psWarning("Unable to query database for concept %s --- ignored.", name);
    408                 psFree(sql);
    409                 continue;
    410             }
    411             psFree(sql);
    412 
    413             psArray *rows = p_psDBFetchResult(db); // Rows returned from the query
    414             if (rows->n == 0) {
    415                 psWarning("No rows returned from database query for concept %s --- ignored.", name);
    416                 continue;
    417             }
    418             if (rows->n > 1) {
    419                 psWarning("Multiple rows returned from database query for concept %s --- using the first",
    420                           name);
    421             }
    422             psMetadata *row = rows->data[0]; // First (and only) row
    423             if (row->list->n > 1) {
    424                 psWarning("Multiple columns returned from database query for concept %s --- using the first",
    425                           name);
    426             }
    427             psMetadataItem *conceptItem = psMetadataGet(row, PS_LIST_HEAD); // Item of interest
    428 
    429             // Now we have the result
    430             if (!conceptParse(spec, conceptItem, PM_CONCEPT_SOURCE_DATABASE,
    431                               cameraFormat, target, fpa, chip, cell)) {
    432                 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to parse concept %s from database.\n",
    433                         name);
    434                 status = false;
    435             }
     436        psMetadataItem *conceptItem = p_pmConceptsReadSingleFromDatabase(name, dbSpec, db, fpa, chip, cell);
     437        if (conceptItem && !conceptParse(spec, conceptItem, PM_CONCEPT_SOURCE_DATABASE,
     438                                         cameraFormat, target, fpa, chip, cell)) {
     439            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to parse concept %s from database.\n", name);
     440            status = false;
    436441        }
    437442    } // Iterating through the concept specifications
  • trunk/psModules/src/concepts/pmConceptsRead.h

    r12696 r17911  
    44 * @author Paul Price, IfA
    55 *
    6  * @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
    7  * @date $Date: 2007-03-30 21:12:56 $
     6 * @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
     7 * @date $Date: 2008-06-05 01:31:33 $
    88 * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
    99 */
     
    2222                               const pmCell *cell ///< The cell
    2323                              );
     24
     25/// Read a single concept from the DEFAULTS in the camera format
     26///
     27/// The returned item is NOT parsed, but any interpolation for DEPEND is done.
     28psMetadataItem *p_pmConceptsReadSingleFromDefaults(
     29    const char *name,                   ///< Name of concept
     30    const psMetadata *defaults,         ///< DEFAULTS specifications
     31    const pmFPA *fpa,                   ///< The FPA
     32    const pmChip *chip,                 ///< The chip, or NULL
     33    const pmCell *cell                  ///< The cell, or NULL
     34    );
    2435
    2536/// Read concepts from the DEFAULTS in the camera format file.
     
    4556                               );
    4657
     58/// Read a single concept from the DATABASE specification in the camera format
     59///
     60/// The returned item is NOT parsed, but any interpolation for DEPEND is done.
     61psMetadataItem *p_pmConceptsReadSingleFromDatabase(
     62    const char *name,                   ///< Name of concept
     63    const psMetadata *database,         ///< DATABASE specification
     64    psDB *db,                           ///< Database handle
     65    const pmFPA *fpa,                   ///< The FPA
     66    const pmChip *chip,                 ///< The chip, or NULL
     67    const pmCell *cell                  ///< The cell, or NULL
     68    );
     69
    4770/// Read concepts from the header DATABASE in the camera format file.
    4871///
  • trunk/psModules/src/concepts/pmConceptsWrite.c

    r12890 r17911  
    66#include <assert.h>
    77#include <string.h>
    8 #include <strings.h>            /* for strn?casecmp */
     8#include <strings.h>            /* for strn?casecmp */
    99#include <pslib.h>
    1010
     
    340340        pmConceptSpec *spec = specItem->data.V; // The specification
    341341        psString name = specItem->name; // The concept name
    342         psMetadataItem *defaultItem = psMetadataLookup(defaults, name); // The item from the DEFAULTS
    343         if (defaultItem) {
    344             psMetadataItem *conceptItem = NULL; // The item from the concepts
    345             if (defaultItem->type == PS_DATA_METADATA) {
    346                 // It's a menu --- need to look up the .DEPEND
    347                 psString dependName = NULL; // The concept name with ".DEPEND" on the end
    348                 psStringAppend(&dependName, "%s.DEPEND", defaultItem->name);
    349                 psString dependKey = psMetadataLookupStr(&mdok, defaults, dependName); // The keyword
    350                 if (!mdok || !dependKey || strlen(dependKey) == 0) {
    351                     psWarning("Can't find %s in the DEFAULTS for %s --- ignored.\n",
    352                              dependName, name);
    353                     psFree(dependName);
    354                     continue;
    355                 }
    356                 psString dependValue = psMetadataLookupStr(&mdok, concepts, dependKey); // The value
    357                 if (!mdok || !dependValue || strlen(dependValue) == 0) {
    358                     psWarning("Concept %s specified by %s isn't of type STR -- "
    359                              "ignored.\n", dependKey, dependName);
    360                     psFree(dependName);
    361                     continue;
    362                 }
    363                 // Get the actual item of interest, and correct the name to match the concept name
    364                 defaultItem = psMetadataLookup(defaultItem->data.md, dependValue);
    365                 if (!defaultItem) {
    366                     psWarning("Concept dependency name %s is not found "
    367                              "in concept table for %s -- ignored.\n", dependValue, dependName);
    368                     psFree(dependName);
    369                     continue;
    370                 }
    371                 defaultItem = psMetadataItemCopy(defaultItem);
    372                 psFree(dependName);
    373                 psFree(defaultItem->name);
    374                 defaultItem->name = psStringCopy(name);
    375             } else {
    376                 psMemIncrRefCounter(defaultItem);
    377             }
    378             conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
    379             psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_DEFAULTS,
    380                                                       cameraFormat, fpa, chip, cell);
    381             if (!formatted) {
    382                 continue;
    383             }
    384             if (! compareConcepts(formatted, defaultItem)) {
    385                 psWarning("Concept %s is specified by the DEFAULTS in the camera "
    386                          "format, but the values don't match.\n", name);
    387             }
    388             psFree(defaultItem);
    389             psFree(formatted);
    390         }
     342
     343        psMetadataItem *defaultItem = p_pmConceptsReadSingleFromDefaults(name, defaults, fpa, chip, cell);
     344        if (!defaultItem) {
     345            continue;
     346        }
     347        psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
     348        psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_DEFAULTS,
     349                                                  cameraFormat, fpa, chip, cell);
     350        if (!formatted) {
     351            continue;
     352        }
     353
     354        if (strcmp(defaultItem->name, name) != 0) {
     355            // Correct the name to match the concept name
     356            defaultItem = psMetadataItemCopy(defaultItem);
     357            psFree(defaultItem->name);
     358            defaultItem->name = psStringCopy(name);
     359        } else {
     360            psMemIncrRefCounter(defaultItem);
     361        }
     362
     363        if (!compareConcepts(formatted, defaultItem)) {
     364            psWarning("Concept %s is specified by the DEFAULTS in the camera "
     365                      "format, but the values don't match.\n", name);
     366        }
     367        psFree(defaultItem);
     368        psFree(formatted);
    391369    }
    392370    psFree(specsIter);
     
    418396        psString name = specItem->name; // The concept name
    419397        psMetadataItem *headerItem = psMetadataLookup(translation, name); // The item from the TRANSLATION
    420         if (headerItem) {
    421             if (headerItem->type != PS_DATA_STRING) {
    422                 psWarning("TRANSLATION keyword for concept %s isn't of type STR ---"
    423                          " ignored.", name);
     398        if (!headerItem) {
     399            continue;
     400        }
     401        if (headerItem->type == PS_DATA_METADATA) {
     402            // This is a menu
     403            psTrace("psModules.concepts", 5, "%s is of type METADATA.\n", name);
     404            headerItem = p_pmConceptsDepend(name, headerItem->data.md, translation, fpa, chip, cell);
     405            if (!headerItem) {
    424406                continue;
    425407            }
    426             psTrace("psModules.concepts", 3, "Writing %s to header %s\n", name, headerItem->data.str);
    427             psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
    428             psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_HEADER,
    429                                                       cameraFormat, fpa, chip, cell);
    430             if (!formatted) {
    431                 continue;
    432             }
    433             writeHeader(hdu, headerItem->data.V, formatted);
    434             psFree(formatted);
    435         }
     408        }
     409        if (headerItem->type != PS_DATA_STRING) {
     410            psWarning("TRANSLATION keyword for concept %s isn't of type STR --- ignored.", name);
     411            continue;
     412        }
     413        psTrace("psModules.concepts", 3, "Writing %s to header %s\n", name, headerItem->data.str);
     414        psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
     415        psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_HEADER,
     416                                                  cameraFormat, fpa, chip, cell);
     417        if (!formatted) {
     418            continue;
     419        }
     420        writeHeader(hdu, headerItem->data.V, formatted);
     421        psFree(formatted);
    436422    }
    437423    psFree(specsIter);
     
    470456        psString name = specItem->name; // The concept name
    471457
    472         psMetadataItem *dbItem = psMetadataLookup(database, name); // The item from the DATABASE
    473         if (dbItem) {
    474             if (dbItem->type != PS_DATA_METADATA) {
    475                 psWarning("DATABASE keyword for concept %s isn't of type METADATA "
    476                          "--- ignored.\n", name);
    477                 continue;
    478             }
    479 
    480             psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
    481             psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_DATABASE,
    482                                                       cameraFormat, fpa, chip, cell);
    483             if (!formatted) {
    484                 continue;
    485             }
    486 
    487             psMetadata *dbLookup = dbItem->data.V; // How to look up the value of interest
    488             // Name of the table
    489             const char *tableName = psMetadataLookupStr(&mdok, dbLookup, "TABLE");
    490             // Name of "where" columns
    491             const char *givenCols = psMetadataLookupStr(&mdok, dbLookup, "GIVENDBCOL");
    492             // Values for "where" columns
    493             const char *givenPS = psMetadataLookupStr(&mdok, dbLookup, "GIVENPS");
    494 
    495             // Now, need to get the "given"s
    496             if (strlen(givenCols) || strlen(givenPS)) {
    497                 psList *cols = psStringSplit(givenCols, ",;", true); // List of column names
    498                 psList *values = psStringSplit(givenPS, ",;", true); // List of value names for the columns
    499                 psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB
    500                 if (cols->n != values->n) {
    501                     psLogMsg(__func__, PS_LOG_WARN,
    502                              "The GIVENDBCOL and GIVENPS entries for %s do not have "
    503                              "the same number of entries --- ignored.\n", name);
    504                 } else {
    505                     // Iterators for the lists
    506                     psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false);
    507                     psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false);
    508                     char *column = NULL;    // Name of the column
    509                     while ((column = psListGetAndIncrement(colsIter))) {
    510                         char *dependName = psListGetAndIncrement(valuesIter); // Name for the value
    511                         if (!strlen(column) || !strlen(name)) {
    512                             psWarning("One of the columns or value names for %s is "
    513                                      " empty --- ignored.\n", name);
    514                         } else {
    515                             // Search for the value name
    516                             psMetadataItem *item = NULL; // The value
    517                             if (!item && cell) {
    518                                 item = psMetadataLookup(cell->concepts, dependName);
    519                             }
    520                             if (!item && chip) {
    521                                 item = psMetadataLookup(chip->concepts, dependName);
    522                             }
    523                             if (!item && fpa) {
    524                                 item = psMetadataLookup(fpa->concepts, dependName);
    525                             }
    526                             if (! item) {
    527                                 psLogMsg(__func__, PS_LOG_ERROR,
    528                                          "Unable to find the value name %s for DB "
    529                                          " lookup on %s --- ignored.\n", dependName, name);
    530                             } else {
    531                                 // We need to create a new psMetadataItem.  I don't think we can't simply
    532                                 // hack the existing one, since that could conceivably cause memory leaks
    533                                 psMetadataAddItem(selection, formatted, PS_LIST_TAIL, PS_META_REPLACE);
    534                                 psFree(formatted);
    535                             }
    536                         }
    537                         psFree(dependName);
    538                         psFree(column);
    539                     } // Iterating through the columns
    540                     psFree(colsIter);
    541                     psFree(valuesIter);
    542 
    543                     // Check first to make sure we're only going to touch one row
    544                     psArray *dbResult = psDBSelectRows(db, tableName, selection, 2); // Lookup result
    545                     // Note that we use limit=2 in order to test if there are multiple rows returned
    546                     if (! dbResult || dbResult->n == 0) {
    547                         psWarning("Unable to find any rows in DB for %s --- "
    548                                  "ignored\n", name);
    549                         return false;
    550                     } else {
    551                         if (dbResult->n > 1) {
    552                             psWarning("Multiple rows returned in DB lookup for %s "
    553                                      "--- ignored.\n", name);
    554                         }
    555                         // Update the DB
    556                         psMetadata *update = psMetadataAlloc();
    557                         psMetadataAddItem(update, conceptItem, PS_LIST_HEAD, 0);
    558                         psDBUpdateRows(db, tableName, selection, update);
    559                         psFree(update);
    560                         return true;
    561                     }
    562                 }
    563                 psFree(cols);
    564                 psFree(values);
    565             } // Doing the "given"s.
    566         }
     458        psMetadataItem *dbItem = p_pmConceptsReadSingleFromDatabase(name, database, db, fpa, chip, cell);
     459        if (!dbItem) {
     460            continue;
     461        }
     462
     463        psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts
     464        psMetadataItem *formatted = conceptFormat(spec, conceptItem, PM_CONCEPT_SOURCE_DATABASE,
     465                                                  cameraFormat, fpa, chip, cell);
     466        if (!formatted) {
     467            continue;
     468        }
     469
     470        if (strcmp(dbItem->name, name) != 0) {
     471            // Correct the name to match the concept name
     472            dbItem = psMetadataItemCopy(dbItem);
     473            psFree(dbItem->name);
     474            dbItem->name = psStringCopy(name);
     475        } else {
     476            psMemIncrRefCounter(dbItem);
     477        }
     478
     479        if (!compareConcepts(formatted, dbItem)) {
     480            psWarning("Concept %s is specified by the DATABASE in the camera "
     481                      "format, but the values don't match.\n", name);
     482        }
     483        psFree(dbItem);
     484        psFree(formatted);
    567485    }
    568486    psFree(specsIter);
     
    570488    #endif
    571489}
    572 
Note: See TracChangeset for help on using the changeset viewer.