/* This is a module which implements the notion of a dataset. Its is designed for the use with scripting languages. copyright: GPL Mark Koennecke, October 2002 */ #include #include #include #include "nxdataset.h" /*-----------------------------------------------------------------------*/ static int getTypeSize(int typecode){ switch(typecode){ case NX_FLOAT32: case NX_INT32: case NX_UINT32: return 4; break; case NX_FLOAT64: case NX_INT64: case NX_UINT64: return 8; break; case NX_INT16: case NX_UINT16: return 2; break; default: return 1; break; } } /*-----------------------------------------------------------------------*/ pNXDS createNXDataset(int rank, int typecode, int dim[]){ pNXDS pNew = NULL; int i, length; pNew = (pNXDS)malloc(sizeof(NXDS)); if(pNew == NULL){ return NULL; } pNew->dim = (int *)malloc(rank*sizeof(int)); for(i = 0, length = 1; i < rank; i++){ length *= dim[i]; } pNew->u.ptr = malloc(length*getTypeSize(typecode)); if(pNew->dim == NULL || pNew->u.ptr == NULL){ free(pNew); return NULL; } pNew->rank = rank; pNew->type = typecode; pNew->format = NULL; for(i = 0; i < rank; i++){ pNew->dim[i] = dim[i]; } pNew->magic = MAGIC; memset(pNew->u.ptr,0,length*getTypeSize(typecode)); return pNew; } /*---------------------------------------------------------------------*/ pNXDS createTextNXDataset(char *name){ pNXDS pNew = NULL; pNew = (pNXDS)malloc(sizeof(NXDS)); if(pNew == NULL){ return NULL; } pNew->dim = (int *)malloc(sizeof(int)); pNew->u.cPtr = strdup(name); if(pNew->dim == NULL || pNew->u.ptr == NULL){ free(pNew); return NULL; } pNew->rank = 1; pNew->type = NX_CHAR; pNew->magic = MAGIC; pNew->dim[0] = strlen(name); return pNew; } /*-----------------------------------------------------------------------*/ void dropNXDataset(pNXDS dataset){ if(dataset == NULL){ return; } if(dataset->magic != MAGIC){ return; } if(dataset->dim != NULL){ free(dataset->dim); } if(dataset->u.ptr != NULL){ free(dataset->u.ptr); } if(dataset->format != NULL){ free(dataset->format); } free(dataset); } /*-----------------------------------------------------------------------*/ int getNXDatasetRank(pNXDS dataset){ if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } return dataset->rank; } /*-----------------------------------------------------------------------*/ int getNXDatasetDim(pNXDS dataset, int which){ if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } if(which < 0 || which >= dataset->rank){ return 0; } return dataset->dim[which]; } /*------------------------------------------------------------------------*/ int getNXDatasetType(pNXDS dataset){ if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } return dataset->type; } /*--------------------------------------------------------------------*/ int getNXDatasetLength(pNXDS dataset){ int length, i; if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } length = dataset->dim[0]; for(i = 1; i < dataset->rank; i++){ length *= dataset->dim[i]; } return length; } /*---------------------------------------------------------------------*/ int getNXDatasetByteLength(pNXDS dataset){ return getNXDatasetLength(dataset)*getTypeSize(dataset->type); } /*---------------------------------------------------------------------- This calculates an arbitray address in C storage order -----------------------------------------------------------------------*/ static int calculateAddress(pNXDS dataset, int pos[]){ int result, mult; int i, j; result = pos[dataset->rank - 1]; for(i = 0; i < dataset->rank -1; i++){ mult = 1; for(j = dataset->rank -1; j > i; j--){ mult *= dataset->dim[j]; } if(pos[i] < dataset->dim[i] && pos[i] > 0){ result += mult*pos[i]; } } return result; } /*-----------------------------------------------------------------------*/ double getNXDatasetValue(pNXDS dataset, int pos[]){ int address; double value; if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } address = calculateAddress(dataset,pos); return getNXDatasetValueAt(dataset, address); } /*----------------------------------------------------------------------*/ double getNXDatasetValueAt(pNXDS dataset, int address){ double value; if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } switch(dataset->type){ case NX_FLOAT64: value = dataset->u.dPtr[address]; break; case NX_FLOAT32: value = (double)dataset->u.fPtr[address]; break; case NX_INT32: case NX_UINT32: value = (double)dataset->u.iPtr[address]; break; case NX_INT64: case NX_UINT64: value = (double)dataset->u.lPtr[address]; break; case NX_INT16: case NX_UINT16: value = (double)dataset->u.sPtr[address]; break; default: value = (double)dataset->u.cPtr[address]; break; } return value; } /*-----------------------------------------------------------------------*/ char *getNXDatasetText(pNXDS dataset){ char *resultBuffer = NULL; int length, status = 1; if(dataset == NULL){ return strdup("NULL"); } if(dataset->magic != MAGIC){ return strdup("NULL"); } if(dataset->rank > 1){ status = 0; } if(dataset->type == NX_FLOAT32 || dataset->type == NX_FLOAT64 || dataset->type == NX_INT32 || dataset->type == NX_UINT32 || dataset->type == NX_INT64 || dataset->type == NX_UINT64 || dataset->type == NX_INT16 || dataset->type == NX_UINT16 ) { status = 0; } if(status == 0){ return strdup("NO type problem"); }else{ resultBuffer = (char *)malloc((dataset->dim[0]+10)*sizeof(char)); if(resultBuffer == NULL){ return strdup("NO Memory"); } memset(resultBuffer,0,(dataset->dim[0]+10)*sizeof(char)); strncpy(resultBuffer,dataset->u.cPtr,dataset->dim[0]); } return resultBuffer; } /*----------------------------------------------------------------------*/ int putNXDatasetValue(pNXDS dataset, int pos[], double value){ int address; if(dataset == NULL){ return 0; } if(dataset->magic != MAGIC){ return 0; } address = calculateAddress(dataset,pos); return putNXDatasetValueAt(dataset,address,value); } /*---------------------------------------------------------------------*/ int putNXDatasetValueAt(pNXDS dataset, int address, double value){ /* this code is dangerous, it casts without checking the data range. This may cause trouble in some cases */ switch(dataset->type){ case NX_FLOAT64: dataset->u.dPtr[address] = value; break; case NX_FLOAT32: dataset->u.fPtr[address] = (float)value; break; case NX_INT32: case NX_UINT32: dataset->u.iPtr[address] = (int)value; break; case NX_INT64: case NX_UINT64: dataset->u.lPtr[address] = (int64_t)value; break; case NX_INT16: case NX_UINT16: dataset->u.sPtr[address] = (short int)value; break; default: dataset->u.cPtr[address] = (char)value; break; } return 1; } /*---------------------------------------------------------------------- This is working recursively through the dimensions. When at the last: actual copying takes place. -----------------------------------------------------------------------*/ static void copyCutData(pNXDS source, pNXDS target, int sourceDim[], int targetDim[], int start[], int end[], int dim){ int i, length; double val; targetDim[dim] = 0; length = end[dim] - start[dim]; if(dim == source->rank -1){ for(i = 0; i < length; i++){ sourceDim[dim] = start[dim] + i; val = getNXDatasetValue(source,sourceDim); targetDim[dim] = i; putNXDatasetValue(target, targetDim, val); } } else { for(i = 0; i < length; i++){ sourceDim[dim] = start[dim] + i; targetDim[dim] = i; copyCutData(source,target, sourceDim, targetDim, start, end, dim+1); } } } /*-----------------------------------------------------------------------*/ pNXDS cutNXDataset(pNXDS source, int start[], int end[]){ pNXDS result = NULL; int newDim[NX_MAXRANK], i; int sourceDim[NX_MAXRANK], targetDim[NX_MAXRANK]; for(i = 0; i < source->rank; i++){ if(start[i] < 0 || end[i] > source->dim[i]){ fprintf(stderr,"ERROR: invalid boundaries specified for cutting"); return NULL; } newDim[i] = end[i] - start[i]; if(newDim[i] <= 0){ fprintf(stderr,"ERROR: invalid cut limits specified for cutting dataset"); return NULL; } } result = createNXDataset(source->rank, source->type, newDim); if(result == NULL){ fprintf(stderr,"ERROR: out of memory creating result dataset"); return NULL; } copyCutData(source, result, sourceDim, targetDim, start, end, 0); return result; } /*---------------------------------------------------------------------- This recurses through all dimesnions, thereby skipping the summed one. At the end of the rescusion the actual summing is performed. ----------------------------------------------------------------------*/ static void sumData(pNXDS source, pNXDS target, int sourceDim[], int targetDim[], int targetDimCount, int dimNo, int start, int end, int currentDim){ int i, length; double val, sumVal; /* when we have recursed through all dimensions we actually do the sums... */ if(currentDim == source->rank){ length = end - start; sumVal = getNXDatasetValue(target, targetDim); for(i = 0; i < length; i++){ sourceDim[dimNo] = start + i; val = getNXDatasetValue(source,sourceDim); sumVal += val; } putNXDatasetValue(target, targetDim, sumVal); } else { /* jump over the summed dimension while recursing through the dimensions */ if(currentDim == dimNo){ sumData(source,target,sourceDim, targetDim,targetDimCount, dimNo,start,end,currentDim+1); } else { /* loop over all values of the non summed dimension */ for(i = 0; i < source->dim[currentDim]; i++){ /* the problem here is that we have to jump over the summed dimension here. This why we have to maintain a separate dimension count for the target array. Jumping is done above. */ targetDim[targetDimCount] = i; targetDimCount++; sourceDim[currentDim] = i; sumData(source,target,sourceDim,targetDim,targetDimCount, dimNo,start,end,currentDim+1); targetDimCount--; } } } } /*-----------------------------------------------------------------------*/ pNXDS sumNXDataset(pNXDS source, int dimNo, int start, int end){ int newDim[NX_MAXRANK], targetDim[NX_MAXRANK], sourceDim[NX_MAXRANK]; pNXDS result = NULL; int i, count; if(dimNo < 0 || dimNo > source->rank-1) { fprintf(stderr,"ERROR: invalid dimension for summing requested"); return NULL; } /* make result dataset with missing summed dimension */ for(i = 0, count = 0; i < source->rank; i++){ if(i != dimNo){ newDim[count] = source->dim[i]; count++; } } result = createNXDataset(source->rank-1, source->type, newDim); if(result == NULL){ fprintf(stderr,"ERROR: out of memory creating result dataset"); return NULL; } sumData(source,result,sourceDim,targetDim,0, dimNo, start, end, 0); return result; }