Ejemplo n.º 1
0
int allocAsnInfo (AsnInfo *asn, int numsp, int *spmems) {

    extern int status;

    /* Local variables */
    int i;		/* loop index */
    int prodid = 0;	/* product ID: for looping over products later */
    int j;		/* loop index for EXPs */
    int numexp;	

    /* Function definitions */
    void initAsnProduct (ProdInfo *, int);
    void initAsnSubProd (SubProdInfo *, int);
    void initAsnExp (ExpInfo *);

    void freeAsnInfo (AsnInfo *);
    void initAsnExp (ExpInfo *);

    /* Free the structure if necessary */
    if (asn->product != NULL)
        freeAsnInfo(asn);

    /* Allocate the member structures */
    asn->spmems  = (int *)calloc(numsp+1,sizeof(int));
    asn->product = (ProdInfo *)calloc(1,sizeof(ProdInfo ));

    /* Initialize each member structure */
    for (i=0; i < asn->numprod; i++) {
        initAsnProduct (&(asn->product[i]), numsp+1);
    }

    asn->product[prodid].subprod =
        (SubProdInfo *)calloc(numsp+1, sizeof(SubProdInfo));

    for (i=0; i <= numsp; i++) {
        if (spmems[i] > 0) 
            numexp = spmems[i];
        else
            numexp = 1;

        initAsnSubProd(&(asn->product[prodid].subprod[i]), numexp);
    }

    for (i=0; i <= numsp; i++) {
        asn->product[0].subprod[i].exp =
            (ExpInfo *)calloc(spmems[i]+1, sizeof(ExpInfo));
        for (j=0; j <= spmems[i]; j++)
            initAsnExp (&(asn->product[prodid].subprod[i].exp[j]));	
    }

    /* Check for error during allocation */
    if (asn->product == NULL) {
        asn->numprod = 0;
        asn->numasn = 0;
        trlerror ("Insufficient memory to allocate ASN structure");
        return (status = 1);
    }

    /* Succesful return */
    return (status);
}
Ejemplo n.º 2
0
int GetAsnTable (AsnInfo *asn) {

    /* Arguments:
     **	asn		o: Association info structure
     */
    extern int status;

    /* Local variables */
    int i;				/* loop index */
    int nrows;			/* number of rows in ASNTAB */
    int col, row;			/* loop indexes */
    IRAFPointer tp;			/* ASNTAB table pointer */
    IRAFPointer colptr[NCOLS];	/* ASNTAB column pointers */
    int numsp;			/* number of sub-products in asn */
    int	posid;			/* id of sub-product */
    RowInfo *exp;		/* Internal structure for table information */
    int *spmems, *expmem;	/* number of EXP for each sub-product */
    int poslen;		/* Length of memtype string minus POSID */
    int prodid;		/* id of product 	*/
    int expid;
    int defid;		/* default position id for exposures */
    int procprod;
    int maxspmems;		/* max number of sub-product members */
    char *word;
    Bool proddth;
    char spname_ext[SZ_CBUF+1];	/* Extension for sub-product */
    char spname_ext_cte[SZ_CBUF+1];	/* Extension for sub-product */
    char memtype[SZ_COLNAME+1];
    char memsubtype[SZ_COLNAME+1];

    /* ASNTAB column names */
    char colname[NCOLS][SZ_COLNAME+1] = {
        "MEMNAME",
        "MEMTYPE",
        "MEMPRSNT"
    };

    /* Function definitions */
    void freeAsnInfo (AsnInfo *);
    int  allocAsnInfo (AsnInfo *, int, int *);
    void trlopenerr (char *);
    void trlwarn (char *);
    char *lowcase (char *, char *);
    int  MkName (char *, char *, char *, char *, char *, int);
    void initRowInfo (RowInfo *);
    int  streq_ic (char *, char *);  /* strings equal? (case insensitive) */

    if (asn->debug) {
        sprintf (MsgText, "GetAsnTable: ASN_TABLE is %s",asn->asn_table);
        trlmessage (MsgText); 
    }

    /* Open the ASN table */
    tp = c_tbtopn (asn->asn_table, IRAF_READ_ONLY, 0);
    if (c_iraferr()) {
        trlopenerr (asn->asn_table);
        return (status = TABLE_ERROR);
    }

    /* Get pointers to columns in ASNTAB */
    for (col=0; col < NCOLS; col++) {
        c_tbcfnd1 (tp, colname[col], &(colptr[col]));
        if (c_iraferr() || colptr[col] == 0) {
            sprintf (MsgText, "Can't find column %s in %s", colname[col],
                    asn->asn_table);
            trlerror (MsgText);
            c_tbtclo (tp);
            return (status = COLUMN_NOT_FOUND);
        }
    }

    /* Find out how many rows are in ASNTAB */
    nrows = 0;
    nrows = c_tbpsta (tp, TBL_NROWS);
    if (nrows <= 0) {
        sprintf (MsgText, "Invalid number of rows in %s", asn->asn_table);
        trlerror (MsgText);
        c_tbtclo (tp);
        return (status = TABLE_ERROR);
    }

    /* Initialize total number of members based on number of
     ** rows in table */
    asn->numasn = nrows;
    poslen = 0;

    /* Allocate space for internal variables */
    exp = NULL;
    exp = (RowInfo *)calloc(nrows, sizeof(RowInfo));
    for (row = 0; row < nrows; row++)
        initRowInfo (&(exp[row]));

    /* Read each row of ASNTAB into a local structure */
    for (row = 0; row < nrows; row++) {

        /* Get the MEMBER NAME in this row */
        c_tbegtt (tp, colptr[0], row+1, exp[row].memname, SZ_CBUF);
        if (c_iraferr()) {
            sprintf (MsgText, "Can't read %s in row %d in %s", colname[0],
                    row+1, asn->asn_table);
            trlerror (MsgText);
            c_tbtclo (tp);
            free (exp);
            return (status = ELEMENT_NOT_FOUND);
        }

        /* Convert to lowercase for use as a file name */
        for (i = 0; i < strlen(exp[row].memname); i++)
            exp[row].memname[i] = tolower(exp[row].memname[i]);

        /* Get the TYPE in this row */
        c_tbegtt (tp, colptr[1], row+1, exp[row].mtype, SZ_CBUF);
        if (c_iraferr()) {
            sprintf (MsgText, "Can't read %s in row %d in %s", colname[1],
                    row+1, asn->asn_table);
            trlerror (MsgText);
            c_tbtclo (tp);
            free (exp);
            return (status = ELEMENT_NOT_FOUND);
        }

        /* Convert to lowercase for use later in routine.
         ** Also, if a value of MEMTYPE contains a UNDERLINE, then 
         ** record conversion to DASH in trailer file and warn
         ** user to correct the value. */
        lowcase (exp[row].type, exp[row].mtype);
        for (i = 0; i < strlen(exp[row].type); i++) {
            if (exp[row].type[i] == UNDERLINE_CHAR) {       
                exp[row].type[i] = DASH_CHAR;
                sprintf(MsgText, "MEMTYPE %s in row %d was INVALID and needs to be corrected.",
                        exp[row].mtype, row+1);
                trlwarn(MsgText);
            }
        }

        /* Get the STATUS in this row */
        c_tbegtb (tp, colptr[2], row+1, &(exp[row].prsnt));
        if (c_iraferr()) {
            sprintf (MsgText, "Can't read %s in row %d in %s", colname[2],
                    row+1, asn->asn_table);
            trlerror (MsgText);
            c_tbtclo (tp);
            free (exp);
            return (status = ELEMENT_NOT_FOUND);
        }
        if (asn->debug) {
            sprintf (MsgText, "GetAsnTable: Read in row %d from ASN table",
                    row);
            trlmessage (MsgText);
        }
    }

    /*  
     ** Determine whether CRCORR or RPTOBS processing will be required
     ** by searching for MEMTYPE of EXP_CR* or EXP_RPT*, respectively.
     ** Once it is determined, go on to next step...
     */
    for (row = 0; row < nrows; row++) {

        /* Check to see if we need to do CR-SPLIT combination ... */
        if (strstr (exp[row].type, "-cr") != NULL) {
            asn->crcorr = PERFORM;
            asn->rptcorr = OMIT;
            poslen = CRLEN;
            break;

            /* ... or REPEAT-OBS combination ... 	*/
        } else if (strstr (exp[row].type, "-rp") != NULL) { 
            asn->rptcorr = PERFORM;
            asn->crcorr = OMIT;
            poslen = RPTLEN;
            break;

            /* ... or neither at all	*/
        } else {
            asn->rptcorr = OMIT;
            asn->crcorr = OMIT;
            poslen = DTHLEN;
        }	
    }

    /* Default to always perform DRIZCORR step */
    asn->dthcorr = PERFORM;

    if (asn->debug) {
        sprintf (MsgText, "GetAsnTable: CRCORR = %d, RPTCORR = %d",
                asn->crcorr,asn->rptcorr);
        trlmessage (MsgText);
    }

    /* Sort through the list figuring out which are input vs. output
     ** files, and see if any input files are missing. */
    /* Initialize local variables */
    numsp   = 0;
    posid   = 0;
    prodid  = 0;
    proddth = False;
    defid   = 1;

    /* Find out how many products/sub-products are in the association
     ** and determine the posid for each member. */	
    for (row = 0; row < nrows; row++) {
        memtype[0] = '\0';
        memsubtype[0] = '\0';

        /* As long as this is not the final product,
         ** count number of members in each product/sub-product...*/
        if (strstr(exp[row].type,"prod-dth") != NULL) {
            exp[row].posid = 0;	
            posid = 0;	

            /* If we have a dither product listed, we want to eventually
             ** perform dither combining step... */	
            prodid++;
            proddth = True;

            /* We always want to produce a product, but if
             ** not set to PERFORM, then create an empty product... */
            if (asn->dthcorr == OMIT) 
                asn->dthcorr = DUMMY;

        } else {

            strcpy(memtype,exp[row].type);	
            /* Let's start by breaking up the MEMTYPE string */
            word = strtok(memtype,"-");
            strcpy(memsubtype,word);
            /* The end of this second part of MEMTYPE has the POSID */
            word = strtok(NULL,"\n");

            /* If the last character of the memtype is a number or letter, 
             ** convert to an integer value...  */
            if (streq_ic(word,"crj") || streq_ic(word,"rpt") || streq_ic(word,"crc") ) {
                posid = 1;
            } else {
                if (exp[row].prsnt || streq_ic(memsubtype,"prod")) {

                    if (isalnum(word[poslen])) {
                        /* Interpret the POSID from the second part
                         ** of MEMTYPE */
                        posid=(int)strtol(&word[poslen],(char **)NULL,10);
                    } else {
                        /* Otherwise, assume it is a different pointing
                         ** and assign an incremented position ID. After
                         ** all, it is NOT a CR-SPLIT or RPT-OBS exposure.*/
                        posid = defid;
                        defid++;
                    }
                }
            }

            /* Keep track of how many sub-products there are based on
             ** POSID from MEMTYPE values */

            if (posid > numsp) {
                if ((exp[row].prsnt && (strstr(memtype,"exp") != NULL)) ||
                        strstr(memtype,"prod") != NULL) {
                    numsp++;
                }
            }

            exp[row].posid = posid;		
        }

        if (asn->debug) {
            sprintf (MsgText, "GetAsnTable: Posid = %d for row %d",posid,
                    row);
            trlmessage (MsgText);
        }	

        /* If the member is missing, give a warning */
        /* This implies that MEMPRSNT must be set to YES for EXP_*
         ** This is not fatal for WF3.  Simply decrement tmembers. */
        if (!exp[row].prsnt && strncmp(exp[row].type, "prod-",5) != 0) {
            sprintf (MsgText, "Member \"%s\" is not present",
                    exp[row].memname);
            trlwarn (MsgText);		 
            asn->numasn--;
            /* Now flag row as being absent so it doesn't get passed
             ** along for further processing... */
            exp[row].posid = MEMABSENT;
        }
    }

    if (asn->debug) {
        sprintf (MsgText, "GetAsnTable: NUMSP = %d, PRODID = %d",numsp,
                prodid);
        trlmessage (MsgText);
    }

    /* Check for existence of enough data to process */
    if (asn->numasn < 1) {
        trlerror ("No data available for given assoc. table");
        freeAsnInfo (asn);
        return (status = ERROR_RETURN);
    }

    /* Record the number of products found in association */
    if (proddth) {
        asn->numprod = prodid;
    } else {
        /* If there are no PROD-DTH entries in ASN table, set
         ** numprod to 1 */
        asn->numprod = prodid + 1;
    }

    /* Determine what elements should be processed based on
     ** initial input, either FULL or PARTIAL processing.  */
    procprod = 0;
    if (asn->process != FULL) {
        for (row=0; row < nrows; row++){
            /* Look for entry with same name as input */
            if (streq_ic(exp[row].memname, asn->rootname)) {
                /* We only want to process this product	*/
                procprod = exp[row].posid;
                numsp = 1;
            }	
        }
    }

    /* Allocate space to count number of exposures per sub-product
     ** with spmems[0] being reserved for final output product
     ** since POSID starts indexing at 1. */
    spmems = (int *)calloc(numsp+1,sizeof(int));
    expmem = (int *)calloc(numsp+1,sizeof(int));

    /* Initialize arrays */
    for (i=0; i <= numsp; i++) {
        spmems[i] = 0;
        expmem[i] = 0;
    }

    /* For each sub-product,
     ** identify each EXP that belongs to that posid and 
     ** is present to be processed. */
    for (row=0; row < nrows; row++) {
        if (strstr(exp[row].type, "exp-") && exp[row].posid > MEMABSENT) {

            if ((asn->process != FULL && exp[row].posid == procprod) ||
                    asn->process == FULL) {

                spmems[exp[row].posid]++;
                /* Exposure IDs will start at 1 to be consistent 
                 ** with POSID numbering. Initialize here, count later. */
                expmem[exp[row].posid] = 1;
            }
        }
    }

    /* Allocate slots for all members in ASN info structure */
    if (allocAsnInfo (asn, numsp, spmems)) {
        return (status = TABLE_ERROR);
    }

    asn->product[prodid].prodid = prodid;

    /* Reset prodid for filling ASN table */
    prodid = 0;

    /* Copy summary information about ASN relationships to ASN structure. */
    maxspmems = 0;
    asn->numsp = numsp;
    for (i=0; i <= numsp; i++) {
        asn->spmems[i] = spmems[i];
        if (spmems[i] > maxspmems)
            maxspmems = spmems[i];
    }

    /* If there aren't any sub-products with more than 1 member, then
     ** omit crcorr/rptcorr processing */
    if ((maxspmems < 2) && asn->crcorr == PERFORM) {
        sprintf (MsgText,
                "No sub-product with more than 1 member; CRCORR will be skipped");
        trlwarn (MsgText);
        asn->crcorr = DUMMY;
    } else if ((maxspmems < 2) && asn->rptcorr == PERFORM) {
        sprintf (MsgText,
                "No sub-product with more than 1 member; RPTCORR will be skipped");
        trlwarn (MsgText);
        asn->rptcorr = DUMMY;
    }

    /* Copy information read-in into ASN structure now... */
    for (row = 0; row < nrows; row++) {
        if (exp[row].posid != MEMABSENT) {
            if ((asn->process != FULL && exp[row].posid == procprod) ||
                    asn->process == FULL) {	  
                posid = exp[row].posid;

                /* Is this row the final product entry? */
                if (strstr(exp[row].type, "prod-dth") != NULL) {
                    strcpy (asn->product[prodid].name, exp[row].memname);
                    strcpy (asn->product[prodid].mtype, exp[row].type);
                    asn->product[prodid].prsnt = exp[row].prsnt;
                    asn->product[prodid].numsp = numsp;
                    asn->product[prodid].asnrow = row+1;

                    /* Create full file name for this image */
                    if (MkName (exp[row].memname, "_raw", "_drz", "",
                                asn->product[prodid].prodname, SZ_LINE)){
                        strcpy(asn->product[prodid].prodname,
                                exp[row].memname);
                        strcat (asn->product[prodid].prodname,
                                "_drz.fits");
                    }
                    
                    /* Create full file name for this CTE image */
                    if (MkName (exp[row].memname, "_rac_tmp", "_drc", "",
                                asn->product[prodid].prodname_cte, SZ_LINE)){
                        strcpy(asn->product[prodid].prodname_cte,
                                exp[row].memname);
                        strcat (asn->product[prodid].prodname_cte,
                                "_drc.fits");
                    }
                    

                    /* Or, is this row an input exposure? */
                } else if (strstr(exp[row].type, "exp-") != NULL) {

                    if (exp[row].posid > MEMABSENT) {

                        /* Internal counter for which exposure we want for
                         ** a position */
                        expid = expmem[posid];
                        strcpy(asn->product[prodid].subprod[posid].exp[expid].name,
                                exp[row].memname);		
                        strcpy(asn->product[prodid].subprod[posid].exp[expid].mtype,
                                exp[row].type);
                        asn->product[prodid].subprod[posid].exp[expid].prsnt =
                            exp[row].prsnt;
                        asn->product[prodid].subprod[posid].exp[expid].asnrow=
                            row+1;

                        /* Create full file name for this image */
                        if (MkName (exp[row].memname, "_raw", "_raw", "",
                                    asn->product[prodid].subprod[posid].exp[expid].expname,
                                    SZ_LINE)) {

                            strcpy(asn->product[prodid].subprod[posid].exp[expid].expname,
                                    exp[row].memname);
                            strcat(asn->product[prodid].subprod[posid].exp[expid].expname,
                                    "_raw.fits");
                        }

                        /* Fill-in sub-product information for EXP-DTH
                         ** exposures which don't create sub-products */
                        if (strstr(exp[row].type, "exp-dth") != NULL) {
                            if (!MkName (exp[row].memname, "_raw", "_flt", "",
                                        asn->product[prodid].subprod[posid].spname,
                                        SZ_LINE) ) {

                                strcpy(asn->product[prodid].subprod[posid].name,
                                        exp[row].memname);
                                strcpy(asn->product[prodid].subprod[posid].mtype,
                                        exp[row].type);
                                asn->product[prodid].subprod[posid].posid =
                                    exp[row].posid;
                            }
                        }

                        /* Increment that counter for next exposure's id
                         ** for this posid */
                        expmem[posid]++;
                    }

                    /* If neither, it must be a sub-product */
                } else {

                    if (spmems[posid] > 0) {

                        strcpy(asn->product[prodid].subprod[posid].name,
                                exp[row].memname);
                        strcpy(asn->product[prodid].subprod[posid].mtype,
                                exp[row].type);
                        asn->product[prodid].subprod[posid].prsnt =
                            exp[row].prsnt;
                        asn->product[prodid].subprod[posid].asnrow = row+1;


                        /* Create full file name for this image for 
                         ** DTHCORR input */
                        spname_ext[0] = '\0';
                        spname_ext_cte[0] = '\0';
                        if (asn->crcorr || asn->rptcorr) {
                            strcpy (spname_ext, "_crj");
                            strcpy (spname_ext_cte,"_crc");
                        } else {
                            strcpy (spname_ext, "_sfl");
                            strcpy (spname_ext_cte, "_sfl");
                        }

                        if (MkName (exp[row].memname, "_raw", spname_ext, "",
                                    asn->product[prodid].subprod[posid].spname,
                                    SZ_LINE)) {

                            strcpy(asn->product[prodid].subprod[posid].spname,
                                    exp[row].memname);
                            strcat(asn->product[prodid].subprod[posid].spname,
                                    spname_ext);		
                            strcat(asn->product[prodid].subprod[posid].spname,
                                    ".fits");		
                                    
                        }
                        if (MkName (exp[row].memname, "_raw", spname_ext_cte, "",
                                    asn->product[prodid].subprod[posid].spname_cte,
                                    SZ_LINE)) {

                            strcpy(asn->product[prodid].subprod[posid].spname_cte,
                                    exp[row].memname);
                            strcat(asn->product[prodid].subprod[posid].spname_cte,
                                    spname_ext_cte);		
                            strcat(asn->product[prodid].subprod[posid].spname_cte,
                                    ".fits");		
                                    
                        }

                        asn->product[prodid].subprod[posid].numexp =
                            spmems[posid];
                        asn->product[prodid].subprod[posid].posid = posid;

                    }
                }
            }
        } /* Process only those exposures where MEMPRSNT == YES */
    }

    /* Close the ASN table.  We are done reading it in. */
    c_tbtclo (tp);



    /* Clean up memory usage as well. */
    free (spmems);
    free (expmem);
    free (exp);

    if (asn->debug) {
        trlmessage ("GetAsnTable: Info from ASN read into memory.");
    }

    /* Successful return */
    return (status);
}
Ejemplo n.º 3
0
int CalAcsRun (char *input, int printtime, int save_tmp, int verbose, int debug, const unsigned nThreads, const unsigned cteAlgorithmGen, const char * pcteTabNameFromCmd) {

    /* arguments:
       char *input     i: name of the FITS file/table to be processed
       int printtime   i: true --> print time stamps at intermediate steps
       int *save_tmp   i: true --> save temporary files
       int verbose     i: true --> print info during processing
       int debug       i: true --> print debugging info during processing
       int onecpu      i: true --> turn off use of OpenMP during processing
    */

    extern int status;

    ACSInfo acshdr;        /* calibration switches, etc */
    AsnInfo    asn;        /* association table data    */

    char *acsdth_input;    /* Input list for ACSDTH */

    int prod;

    void PrBegin (char *);
    void PrEnd (char *);
    void PrFileName (char *, char *);
    void TimeStamp (char *, char *);
    /* Association table routines */
    void initAsnInfo (AsnInfo *);
    void freeAsnInfo (AsnInfo *);
    int LoadAsn (AsnInfo *);
    int ProcessACSCCD (AsnInfo *, ACSInfo *, int *, int, const unsigned nThreads, const unsigned cteAlgorithmGen, const char * pcteTabNameFromCmd);
    int ProcessMAMA (AsnInfo *, ACSInfo *, int);
    int AcsDth (char *, char *, int, int, int);
    char *BuildDthInput (AsnInfo *, int);
    void InitDthTrl (char *, char *);

    /* Post error handler */
    push_hstioerr (errchk);

    PrBegin ("CALACS");    /* *** CALACS -- Version ... *** */

    if (printtime)
    TimeStamp ("CALACS started", "");

    /* Determine if input is a single file or an association
       table, then populate ASN structure with appropriate
       information to control processing.
    */
    initAsnInfo(&asn);

    if (debug) {
        trlmessage ("Initialized Association data ... ");
    }

    /* Copy Input filename to ASN structure    */
    strcpy (asn.input, input);

    /* Print image name. */
    trlmessage ("\n");

    PrFileName ("input", asn.input);

    /* Set verbose flag... */
    asn.verbose = verbose;
    asn.debug = debug;

    /* LoadAsn will determine whether input is a single file or an
       Association table.  If a single image, it will look in that images
       association table to see what products are associated with it, and
       process them accordingly.  If it is just a single image as its
       own output, it will proceed as a 1 element table.
       Based on routines from n_getAsnTable() and n_setup() in CALNICB
    */
    if(LoadAsn(&asn)) {
        freeAsnInfo (&asn);
        return (status);
    }

    /* Check to see that detector is known, as it could come through with a
       value of 0 or UNKNOWN_DETECTOR.
       WJH  2Mar99
    */
    if (asn.detector == UNKNOWN_DETECTOR || asn.detector == 0) {
        trlwarn ("Unknown detector type for observations.");
        freeAsnInfo(&asn);
        return (status = NOTHING_TO_DO);
    }

    if (asn.verbose) {
        sprintf (MsgText,"CALACS: Detector %s, type %d ",asn.instr, asn.detector);
        trlmessage (MsgText);
    }

    /* Determine what detector we are working with... */
    if (asn.detector != MAMA_DETECTOR ) {  /* Process CCD data ... */
        if (asn.verbose) {
            trlmessage ("CALACS: processing a CCD product");
        }
        if (ProcessACSCCD(&asn, &acshdr, &save_tmp, printtime, nThreads, cteAlgorithmGen, pcteTabNameFromCmd)) {
            if (status == NOTHING_TO_DO) {
                trlwarn ("No processing desired for CCD data.");
            } else {
                trlerror ("Couldn't process CCD data");
            }

            freeAsnInfo(&asn);
            return (status);
        }
        trlmessage("Finished CCD processing...");
    } else {  /* Process MAMA observations here */

        trlmessage("Starting to process MAMA data now...");

        if (ProcessMAMA(&asn, &acshdr, printtime)) {
            if (status == NOTHING_TO_DO){
                trlwarn ("No processing desired for MAMA data.");
            } else{
                trlerror ("Couldn't process MAMA data");
            }
            freeAsnInfo(&asn);
            return (status);
        }
        trlmessage("Finished MAMA processing...");
    }


    /* Add DTH processing here... */
    /* For each DTH product... */
    if (asn.process == FULL){
        if (asn.verbose) {
            trlmessage ("CALACS: Building DTH products");
        }
        acsdth_input = NULL;
        for (prod = 0; prod < asn.numprod; prod++) {
            /* Create empty DTH product, header only */
            /* This uses only one sub-product for the header template,
               but later versions should use a function similar to
               BuildSumInput to create list of subproducts as inputs...
            */
            acsdth_input = BuildDthInput (&asn, prod);

            /* We always want to create a final concatenated trailer file for
               the entire association whether there is a product or not. So, we
               set up the trailer file based on the association file name itself.
            */

            /* If desired, we could optionally use the full _drz.tra filename
               as the trailer filename, based on the output dither product name.
            if (strcmp(asn.product[prod].prodname,"") != 0) {
                InitDthTrl (acsdth_input, asn.product[prod].prodname);
            } else { */

            InitDthTrl(acsdth_input, asn.rootname);

            /* End brace for optional dither product name assignment...
            } */

            /* Check if we have a PROD-DTH specified...*/
            if (strcmp(asn.product[prod].prodname, "") != 0) {

                if ((asn.dthcorr == PERFORM || asn.dthcorr == DUMMY)) {
                    if (AcsDth (acsdth_input, asn.product[prod].prodname, asn.dthcorr, printtime, asn.verbose) )
                        return (status);

                    /* Pass posid of 0 to indicate a PRODUCT is to be updated */
                    updateAsnTable(&asn, prod, NOPOSID);
                }
            } else {
                trlwarn ("No DTH product name specified. No product created.");
                /*status = ACS_OK; */
            }
        }
        free (acsdth_input);
    }
    if (asn.verbose) {
        trlmessage ("CALACS: Finished processing product ");
    }

    freeAsnInfo(&asn);

    trlmessage ("\n");
    PrEnd ("CALACS");        /* *** CALACS complete *** */

    if (printtime)
    TimeStamp ("CALACS completed", acshdr.rootname);

    /* Return the final value of status, which should be ACS_OK if
       all went well or some error condition otherwise. */
    return (status);
}