/* create a new fut which has shared input tables and calculates the identity function */ fut_p fut_new_empty ( KpInt32_t ndim, KpInt32_p dim, KpInt32_t nchan, PTDataClass_t iClass, PTDataClass_t oClass) { fut_p fut; KpInt32_t iomask = 0, i1; if ((ndim > FUT_NICHAN) || (nchan > FUT_NOCHAN)) { return FUT_NULL; } for (i1 = 0; i1 < ndim; i1++) { iomask |= FUT_IN(FUT_BIT(i1)); } for (i1 = 0; i1 < nchan; i1++) { iomask |= FUT_OUT(FUT_BIT(i1)); } /* Compute shared input tables, grid tables, and output tables: */ fut = constructfut (iomask, dim, NULL, NULL, NULL, NULL, iClass, oClass); return (fut); }
fut_p get_linlab_fut (KpInt32_t size, double neutralInput, PTDataClass_t iClass, PTDataClass_t oClass) { fut_p futp; KpInt32_t iomask, sizeArray[KCP_THIS_FUT_CHANS]; fut_ifunc_t ifunArray[KCP_THIS_FUT_CHANS] = {NULL, yzfun, yzfun}; fut_ofunc_t ofunArray[KCP_THIS_FUT_CHANS] = {ofun, ofun, ofun}; fData_t fData; if (iClass) {} if (oClass) {} #if defined KCP_DIAG_LOG {KpChar_t string[256]; sprintf (string, "get_linlab_fut\n size %d, neutralInput %f\n", size, neutralInput); kcpDiagLog (string); } #endif iomask = FUT_IN(FUT_XYZ) | FUT_OUT(FUT_XYZ); /* define neutral input position and grid point */ fData.neutralInput = neutralInput; fData.neutralgrid = (double)(size / 2) / (double)(size - 1); /* assume all dimensions are the same */ sizeArray[0] = size; sizeArray[1] = size; sizeArray[2] = size; futp = constructfut (iomask, sizeArray, &fData.std, ifunArray, NULL, ofunArray, iClass, oClass); #if defined KCP_DIAG_LOG saveFut (futp, "CP24.fut"); #endif return (futp); }
/* fut_new allocates and initializes a new fut_t data structure. * iomask specifies which (common) input tables and which output channels * are being defined. Additional channels may be added later using * fut_defchan. * * NOTES: * 1. All the tables must be packed into a single array. * * 2. If a needed input table is not supplied (as determined from the * grid table) or if a supplied input table is NULL, then a ramp * input table will be automatically generated and inserted into * the common itbl list. The grid sizes are inferred from the * supplied grid tables. */ fut_p fut_new ( KpInt32_t iomask, fut_itbl_p FAR* itbls, fut_gtbl_p FAR* gtbls, fut_otbl_p FAR* otbls) { fut_itbl_p itbl[FUT_NICHAN]; fut_otbl_p otbl[FUT_NOCHAN]; fut_gtbl_p gtbl[FUT_NOCHAN]; fut_p fut; KpInt32_t tIndex, imask, omask, i; /* get input and output masks */ imask = (KpInt32_t)FUT_IMASK(iomask); omask = (KpInt32_t)FUT_OMASK(iomask); if ( imask > FUT_ALLIN || omask > FUT_ALLOUT ) { DIAG("fut_new: too many input or output channels.\n", 0); return (NULL); } /* get args specified by iomask */ for ( i=0, tIndex = 0; i<FUT_NICHAN; i++ ) { itbl[i] = (((imask & FUT_BIT(i)) != 0) && (itbls != NULL)) ? itbls[tIndex++] : FUT_NULL_ITBL; } for ( i=0, tIndex = 0; i<FUT_NOCHAN; i++ ) { gtbl[i] = FUT_NULL_GTBL; otbl[i] = FUT_NULL_OTBL; if ((omask & FUT_BIT(i)) != 0) { if (gtbls != NULL) { gtbl[i] = gtbls[tIndex]; } if (otbls != NULL) { otbl[i] = otbls[tIndex]; } tIndex++; } } /* allocate and clear the fut_t structure */ fut = fut_alloc_fut (); if ( fut == NULL ) { return (NULL); } /* set the interpolation order */ fut->iomask.order = (KpInt32_t)FUT_ORDMASK(iomask); /* insert the specified input tables */ for ( i=0; i<FUT_NICHAN; i++ ) { if ( itbl[i] == NULL) continue; if ( ! IS_ITBL (itbl[i]) ) { fut_free (fut); return (NULL); } fut->iomask.in |= FUT_BIT(i); fut->itbl[i] = fut_share_itbl(itbl[i]); fut->itblHandle[i] = fut->itbl[i]->handle; } /* define the specified output channels */ for ( i=0; i<FUT_NOCHAN; i++ ) { if ( gtbl[i] == NULL) continue; if ( ! fut_defchan(fut,FUT_OUT(FUT_BIT(i)),NULL,gtbl[i],otbl[i]) ) { fut_free (fut); return (NULL); } } fut->lutConfig = LUT_TYPE_UNKNOWN; return (fut); }
fut_p fut_resize ( fut_p fut, KpInt32_p sizeArray) { fut_p reSizedGtblFut = NULL, gtblFut = NULL, reSizedFut = NULL, identityFut = NULL; KpInt32_t i1, i2, iomask, iiomask, imask, omask, sameDims; fut_chan_p chan; fut_itbl_p itbl, itbls[FUT_NICHAN]; fut_gtbl_p gtbls[FUT_NOCHAN]; fut_otbl_p otbls[FUT_NOCHAN]; #if defined KCP_DIAG_LOG kcpDiagLog ("fut_resize\n"); #endif if ( ! IS_FUT(fut)) { return NULL; } for (i1 = 0; i1 < FUT_NICHAN; i1++) { itbls[i1] = FUT_NULL_ITBL; /* init to null for freeing on error */ } /* collect the gtbls from the source fut */ /* make sure that all the gtbls use the same itbls */ omask = 0; for (i1 = 0, sameDims = 1; i1 < FUT_NOCHAN; i1++) { chan = fut->chan[i1]; if (IS_CHAN(chan)) { for (i2 = 0; i2 < FUT_NICHAN; i2++) { itbl = fut->itbl[i2]; if (chan->itbl[i2] != itbl) { /* must be shared */ goto GetOut; } if (IS_ITBL(itbl)) { if (itbl->size != sizeArray [i2]) { sameDims = 0; /* not the same */ } } } omask |= FUT_BIT(i1); /* resize this chan */ gtbls[i1] = chan->gtbl; /* collect gtbls */ } else { gtbls[i1] = NULL; } } if (sameDims == 1) { return fut; /* already the right size! */ } imask = fut->iomask.in; iomask = FUT_OUT(omask) | FUT_IN(imask); /* make a new fut with these gtbls and identity itbls and otbls */ gtblFut = fut_new (iomask, NULL, gtbls, NULL); if (gtblFut != NULL) { /* make an identity fut with itbls that have the specified sizes */ iiomask = FUT_OUT(imask) | FUT_IN(imask); identityFut = constructfut (iiomask, sizeArray, NULL, NULL, NULL, NULL, KCP_FIXED_RANGE, KCP_FIXED_RANGE); if (identityFut != NULL) { /* compose the new size fut with the gtbl fut */ reSizedGtblFut = fut_comp (gtblFut, identityFut, 0); if (reSizedGtblFut != NULL) { /* make a new fut with original itbls, ... */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((imask & FUT_BIT(i1)) != 0) { itbls[i1] = fut_copy_itbl (fut->itbl[i1]); /* copy (do not share!) original itbls */ if (itbls[i1] == NULL) { goto GetOut; } makeMftiTblDat (itbls[i1]); /* convert to mft to remove grid size dependancy */ itbls[i1]->size = reSizedGtblFut->itbl[i1]->size; /* set new grid size */ fut_free_itbldat (itbls[i1], freeData); /* free fixed table, it has incorrect grid indices */ } } /* ... resized gtbls, and original otbls */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { if ((omask & FUT_BIT(i1)) != 0) { gtbls[i1] = reSizedGtblFut->chan[i1]->gtbl; /* collect resized gtbls */ otbls[i1] = fut->chan[i1]->otbl; /* and original otbls */ } else { gtbls[i1] = NULL; otbls[i1] = NULL; } } reSizedFut = fut_new (iomask, itbls, gtbls, otbls); } } } GetOut: fut_free (reSizedGtblFut); /* free the intermediate futs */ fut_free (gtblFut); fut_free (identityFut); fut_free_tbls (FUT_NICHAN, (void **)itbls); return (reSizedFut); }
fut_p fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask) { KpInt32_t ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans; fut_p fut2 = NULL, evalFut = NULL; fut_itbl_p oitbls[FUT_NICHAN]; mf2_tbldat_p indat[FUT_NICHAN], outdat[FUT_NOCHAN]; fut_gtbl_p fut1_gtbls[FUT_NOCHAN]; if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) { return (NULL); } /* extract component masks from iomask */ omask = FUT_OMASK(iomask); /* which output chans? */ pmask = FUT_PMASK(iomask); /* which ones allowed to pass through? */ order = FUT_ORDMASK(iomask); /* which interpolation to use? */ if ( order == FUT_DEFAULT ) { order = fut1->iomask.order; } /* adjust masks for iomask_check below */ pmask &= fut0->iomask.out; /* available for "pass through" */ if ( omask == 0 ) { /* required outputs (0 means all) */ omask = fut1->iomask.out; } /* see if fut0 can provide required inputs to fut1 */ imask = fut0->iomask.out; /* available inputs for fut1 */ iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask); if ( ! fut_iomask_check (fut1, iomask) ) { return (NULL); } /* make sure the futs are in the reference state */ if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) { return (NULL); } /* fut1 will be used to process the grid tables of fut0, placing the * results in the grid tables of fut2. Fut0's grid table data must first * be passed through its output tables before sending it through fut1's * input tables. This is accomplished more efficiently by composing * fut1's input tables with fut0's output tables and using these directly * on fut0 grid data rather than the normal input tables. * * Create the result fut (fut2) which will be the composition of fut1 * and fut0. Fut2 will inherit the input tables of fut0 and the output * tables of fut1. Its grid data will be in the same color coordinates * as fut1's. */ fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL); if ( fut2 == NULL ) { return (NULL); } /* for each desired channel i in fut2, create a new grid table. The * dimensions of each new grid table are derived from fut0 and fut1 * like so: for every input required for channel i of fut1, form the * union of the input sets of all corresponding fut0 outputs. */ /* null all io tables and table pointers */ KpMemSet (oitbls, 0, sizeof(oitbls)); imask = 0; /* will be the input mask for all inputs needed to fut1 */ evalomask = 0; /* omask for evaluation */ for (i = 0; (i < FUT_NOCHAN) && ok; i++) { KpInt32_t size[FUT_NICHAN]; fut_gtbl_p gtbl; KpInt32_t imask1, imask2; fut1_gtbls[i] = NULL; /* assume not needed */ if ((omask & FUT_BIT(i)) == 0) { /* is this output channel needed? */ continue; /* no */ } /* if a specified output is to be passed through from fut0, do that here */ if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) { ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, fut0->chan[i]->gtbl, fut0->chan[i]->otbl); continue; /* no need to evaluate this ochan */ } if (! IS_CHAN(fut1->chan[i])) { ok = 0; /* something wrong */ goto GetOut; } /* At this point we know that (fut1->chan[i] != 0). We also * have determined (from iomask_check above) that fut0->chan[j] != 0. */ imask2 = 0; /* determine inputs from fut0 needed for this channel */ imask1 = fut1->chan[i]->imask; /* inputs used by this chan */ for (j = 0; (j < FUT_NICHAN) && ok; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this input chan is needed */ if ( ! IS_CHAN(fut0->chan[j])) { /* available? */ ok = 0; /* composition fails */ goto GetOut; } if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) { /* shared itbl? */ goto nextOChan; /* nope, ignore this ochan */ } imask2 |= fut0->chan[j]->imask; } } evalomask |= FUT_BIT(i); /* will be evalutating this channel */ imask |= imask1; /* build mask of all needed inputs */ /* determine required dimensions from mask */ for (j = 0; j < FUT_NICHAN; j++) { size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1; } /* create the new grid table * insert it along with fut1's output table into fut2 */ gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size); ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl); fut_free_gtbl (gtbl); if (!ok) { goto GetOut; } fut1_gtbls[i] = fut1->chan[i]->gtbl; /* collect gtbls for evaluation fut */ /* verify the input data for the evaluation of the output channel in fut1 */ for (j = 0; j < FUT_NICHAN; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this channel needed as input */ if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) { /* it's inputs must be used by output */ ok = 0; /* composition fails */ goto GetOut; } } } nextOChan:; } /* collect the gtbls which are the input data for the chan evaluation. * also pre-compose fut0's otbls with fut1's itbls. */ for (i = 0; i < FUT_NICHAN; i++) { oitbls[i] = NULL; if (ok) { fut_chan_p theChan = fut0->chan[i]; if ((imask & FUT_BIT(i)) == 0) { continue; /* this output from fut0 not required */ } indat[i] = theChan->gtbl->refTbl; /* collect gtbls: the input data for the evaluation */ ok = (indat[i] != NULL); /* allocate memory for composed i/o tables * these have the same size as the output tables of the channel supplying the input */ if (ok) { fut_itbl_p theITbl = fut1->itbl[i]; fut_otbl_p theOTbl = theChan->otbl; oitbls[i] = fut_alloc_itbl (); /* get an itbl */ oitbls[i]->size = theITbl->size; oitbls[i]->dataClass = KCP_FIXED_RANGE; nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries); ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL); if (ok) { /* make input table for evaluation */ ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]); } } } } /* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */ evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL); if (( ! ok) || (evalFut == NULL) || /* if evaluation fut ok */ (fut_to_mft (fut2) != 1)) { /* make sure the futs are in the reference state */ ok = 0; goto GetOut; } else { /* Finally, we are ready to pass fut0's grid tables through fut1 */ for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) { if ((evalomask & FUT_BIT(i)) != 0) { fut_gtbl_p gtbl; gtbl = fut2->chan[i]->gtbl; nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t); /* grid points for eval */ if (evalFut->iomask.in != evalFut->chan[i]->imask) { /* must evaluate this channel singly */ evalomask &= ~FUT_BIT(i); /* remove channel from multiple eval list */ ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl)); } else { outdat[nOutChans] = gtbl->refTbl; nOutChans++; } } } /* eval result is composed fut's gtbls */ ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat); } GetOut: /* must always free up the evaluation fut and io tables, even if an error occurred! */ fut_free (evalFut); fut_free_tbls (FUT_NICHAN, (void *)oitbls); /* check for errors */ if ( !ok ) { fut_free (fut2); fut2 = NULL; } return (fut2); }
/* Determine whether or not temporary memory is needed */ static PTErr_t setupEvalList ( KpUInt32_t numPTs, PTTable_p* evalList, KpUInt32_p ioMaskList, PTEvalDTPB_p evalDef, KpUInt32_p tempMemNeeded) { PTErr_t PTErr = KCP_SUCCESS; KpInt32_t i1, i2; KpInt32_t finalOutputs, nOutputs, maxOutputs; KpUInt32_t thisOmask, thisImask; KpInt32_t sizeInData, sizeOutData; fut_chan_p futChan; thisOmask = calcChanMask (evalDef->dataTypeO, evalDef->nOutputs, evalDef->output); /* calculate final output mask */ finalOutputs = calcChans (thisOmask); /* and number of output channels */ /* does the fut have those outputs? */ if ((FFUTP(evalList[numPTs -1]->data)->iomask.out & thisOmask) != thisOmask) { PTErr = KCP_INVAL_EVAL; goto ErrOut; } nOutputs = finalOutputs; /* # outputs of fut at the end of the list */ maxOutputs = 0; /* none yet */ for (i1 = (numPTs -1); i1 >= 0; i1--) { if (nOutputs > maxOutputs) { /* remember max # outputs needed */ maxOutputs = nOutputs; } /* get inputs required for this fut as determined by outputs required from this fut */ thisImask = 0; for (i2 = 0; i2 < FUT_NOCHAN; i2++) { if (thisOmask & FUT_BIT(i2)) { /* is this output channel needed? */ futChan = FCHANP(FFUTP(evalList[i1]->data)->chanHandle[i2]); /* get pointer to chan */ thisImask |= (KpUInt32_t)FUT_CHAN_IMASK(futChan); /* include inputs required for this chan */ } } ioMaskList [i1] = FUT_OUT(thisOmask) | FUT_IN(thisImask); /* store the evaluation I/O mask */ /* set up outputs for preceeding fut in the list */ thisOmask = thisImask; /* which are inputs to this fut */ nOutputs = calcChans (thisOmask); /* get number of output channels */ } thisImask = calcChanMask (evalDef->dataTypeI, evalDef->nInputs, evalDef->input); /* calculate input mask for the first fut */ /* does the first fut have the required inputs? */ if ((thisImask & FFUTP(evalList[0]->data)->iomask.in) != FFUTP(evalList[0]->data)->iomask.in) { PTErr = KCP_INVAL_EVAL; goto ErrOut; } /* Is temporary memory required? */ /* If just one PT, then temporary data memory is not needed */ /* if more than one PT (serial evaluation), then the number and size of the outputs */ /* determines whether or not temporary memory is needed */ PTErr = getDataBytes (evalDef->dataTypeI, &sizeInData); /* get input data size */ if (PTErr != KCP_SUCCESS) { goto ErrOut; } PTErr = getDataBytes (evalDef->dataTypeO, &sizeOutData); /* get output data size */ if (PTErr != KCP_SUCCESS) { goto ErrOut; } if (numPTs == 1) { (*tempMemNeeded) = 0; /* not serial evaluation, no temporary data memory needed */ } else { /* serial evaluation */ /* does this require temporary memory? */ if ((maxOutputs > finalOutputs) || (sizeInData < 2) || (sizeOutData < 2)) { (*tempMemNeeded) = 1; /* yes */ } else { (*tempMemNeeded) = 0; /* no */ } } ErrOut: return PTErr; }