/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include /* * $Header: /home/gda/dxcvs/dx/src/exec/dxmods/_partnbrs.c,v 1.3 1999/05/10 15:45:20 gda Exp $ */ #include #include typedef struct node { struct node *next; int offset; } Node; #define MAXDIM 8 #define MAXNODES MAXDIM*64 static Error RegularPartitionNeighbors(CompositeField); static Error IrregularPartitionNeighbors(CompositeField); Error _dxfPartitionNeighbors(Object o) { int i; Field f; Array c; Class class; class = DXGetObjectClass(o); if (class == CLASS_GROUP) class = DXGetGroupClass((Group)o); if (class == CLASS_FIELD) return OK; if (class != CLASS_COMPOSITEFIELD) { DXSetError(ERROR_INVALID_DATA, "input"); return ERROR; } i = 0; while (NULL != (f = (Field)DXGetEnumeratedMember((Group)o, i++, NULL))) { if (DXEmptyField(f)) continue; c = (Array)DXGetComponentValue(f, "connections"); if (c) break; } if (!f) return OK; if (DXQueryGridConnections(c, NULL, NULL)) return RegularPartitionNeighbors((CompositeField)o); else return IrregularPartitionNeighbors((CompositeField)o); } static Error RegularPartitionNeighbors(CompositeField cf) { struct node Nodes[MAXNODES]; int nextNode = 0; struct node heads[MAXDIM]; int nDim; Field f; int meshOffsets[MAXDIM]; int counts[MAXDIM]; int *indices = NULL; Array conn; int nPartitions; Field *fieldList = NULL; int *grid = NULL; int gridSize; int *iPtr; int strides[MAXDIM]; int i, j, k, offset; Array pnbrs; int *nbrs; for(i=0; NULL != (f = (Field)DXGetEnumeratedMember((Group)cf, i, NULL)); i++) { conn = (Array)DXGetComponentValue(f, "connections"); if (! conn) goto error; if (i == 0) { if (! DXQueryGridConnections(conn, &nDim, NULL)) goto error; for (j = 0; j < nDim; j++) { heads[j].offset = 0; heads[j].next = NULL; counts[j] = 1; } } if (! DXGetMeshOffsets((MeshArray)conn, meshOffsets)) goto error; for (j = 0; j < nDim; j++) { Node *l, *n, *new; l = heads + j; n = l->next; while (n != NULL && n->offset <= meshOffsets[j]) { l = l->next; n = n->next; } if (l->offset == meshOffsets[j]) continue; if (nextNode == MAXNODES) { DXSetError(ERROR_INTERNAL, "ran out of nodes in RegularPartitionNeighbors"); return NULL; } new = Nodes + nextNode++; new->offset = meshOffsets[j]; new->next = n; l->next = new; counts[j]++; } } nPartitions = i; gridSize = counts[0]; for (i = 1; i < nDim; i++) gridSize *= counts[i]; fieldList = (Field *)DXAllocateZero(nPartitions * sizeof(Field)); if (! fieldList) goto error; grid = (int *)DXAllocate(gridSize * sizeof(int)); if (! grid) goto error; memset(grid, -1, sizeof(grid)); indices = (int *)DXAllocate(nDim*nPartitions*sizeof(int)); if (! indices) goto error; strides[0] = 1; for (i = 1; i < nDim; i++) strides[i] = strides[i-1] * counts[i-1]; iPtr = indices; for(i=0; NULL != (f = (Field)DXGetEnumeratedMember((Group)cf, i, NULL)); i++) { fieldList[i] = f; conn = (Array)DXGetComponentValue(f, "connections"); if (! conn) goto error; if (! DXGetMeshOffsets((MeshArray)conn, meshOffsets)) goto error; for (j = 0; j < nDim; j++) { Node *l; l = heads + j; for (k = 0; k < counts[j]; k++, l = l->next) if (l->offset == meshOffsets[j]) break; if (k == counts[j]) { DXSetError(ERROR_INTERNAL, "mesh error"); goto error; } iPtr[j] = k; } offset = iPtr[0]; for (j = 1; j < nDim; j++) offset += iPtr[j]*strides[j]; grid[offset] = i; iPtr += nDim; } iPtr = indices; for (i = 0; i < nPartitions; i++, iPtr += nDim) { offset = iPtr[0]; for (j = 1; j < nDim; j++) offset += iPtr[j]*strides[j]; f = fieldList[grid[offset]]; pnbrs = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); if (! pnbrs) goto error; if (! DXAddArrayData(pnbrs, 0, nDim, NULL)) goto error; if (NULL == (nbrs = (int *)DXGetArrayData(pnbrs))) goto error; for (j = 0; j < nDim; j++) { if (iPtr[j] == 0) *nbrs++ = -1; else *nbrs++ = (int)grid[offset - strides[j]]; if (iPtr[j] == counts[j]-1) *nbrs++ = -1; else *nbrs++ = (int)grid[offset + strides[j]]; } if (! DXSetComponentValue(f, "partition neighbors", (Object)pnbrs)) goto error; } DXFree((Pointer)grid); DXFree((Pointer)fieldList); DXFree((Pointer)indices); return OK; error: DXFree((Pointer)grid); DXFree((Pointer)fieldList); DXFree((Pointer)indices); return ERROR; } struct IPN_pass1_args { Field field; HashTable *hPtr; }; struct IPN_pass2_args { Field *fields; HashTable *hashes; int i, n; }; static Error IPN_pass1(Pointer); static Error IPN_pass2(Pointer); static Error IrregularPartitionNeighbors(CompositeField cf) { Field *fieldList = NULL; HashTable *hashList = NULL; Field f; int i, nPartitions; struct IPN_pass1_args args1; struct IPN_pass2_args args2; for (i = 0; NULL != DXGetEnumeratedMember((Group)cf, i, NULL); i++); nPartitions = i; hashList = (HashTable *)DXAllocateZero(nPartitions * sizeof(HashTable)); if (! hashList) goto error; fieldList = (Field *)DXAllocateZero(nPartitions * sizeof(Field)); if (! fieldList) goto error; if (! DXCreateTaskGroup()) goto error; for (i = 0; i < nPartitions; i++) { fieldList[i] = (Field)DXGetEnumeratedMember((Group)cf, i, NULL); args1.field = fieldList[i]; args1.hPtr = hashList + i; if (! DXAddTask(IPN_pass1, (Pointer)&args1, sizeof(args1), 1.0)) { DXAbortTaskGroup(); goto error; } } if (! DXExecuteTaskGroup() || DXGetError() != ERROR_NONE) goto error; args2.fields = fieldList; args2.hashes = hashList; args2.n = nPartitions; if (! DXCreateTaskGroup()) goto error; for (i = 0; i < nPartitions; i++) { args2.i = i; if (! DXAddTask(IPN_pass2, (Pointer)&args2, sizeof(args2), 1.0)) { DXAbortTaskGroup(); goto error; } } if (! DXExecuteTaskGroup() || DXGetError() != ERROR_NONE) goto error; for (i = 0; i < nPartitions; i++) if (hashList[i]) DXDestroyHash(hashList[i]); DXFree((Pointer)hashList); DXFree((Pointer)fieldList); return OK; error: if (hashList) { for (i = 0; i < nPartitions; i++) if (hashList[i]) DXDestroyHash(hashList[i]); } DXFree((Pointer)hashList); DXFree((Pointer)fieldList); return OK; } typedef struct { float point[3]; int element; int face; } HashItem; static float primes[] = { 143669821.0, 45497241659.0, 1455799321.0}; static PseudoKey FaceHash(Key key) { long l; float *p = ((HashItem *)key)->point; float q; q = (p[0]*primes[0] + p[1]*primes[1] + p[2]*primes[2]); l = *(int *)&q; return (PseudoKey)l; } static int FaceCmp(Key k0, Key k1) { float *p0 = ((HashItem *)k0)->point; float *p1 = ((HashItem *)k0)->point; return p0[0] != p1[0] || p0[1] != p1[1] || p0[2] != p1[2]; } #define SWAP(a,b) {float t=a; a=b; b=t;} #define GET_POINT(index,buf) \ { \ if (points) \ { \ int _i; \ \ float *_src = points + index*nDim; \ for (_i = 0; _i < nDim; _i++) \ buf[_i] = *_src++; \ } \ else \ { \ int _indices[MAXDIM], _i, _j; \ float *_d; \ \ GET_INDICES(index,pCounts,nDim); \ _d = pDeltas; \ for (_i = 0; _i < nDim; _i++) \ buf[_i] = pOrigin[_i]; \ for (_i = 0; _i < nDim; _i++) \ for (_j = 0; _j < nDim; _j++) \ buf[_j] += _indices[_i]*(*_d++);\ } \ } #define GET_ELEMENT(index) \ { \ if (elements) \ { \ elt = elements + index*nVerts; \ } \ else \ { \ int _indices[MAXDIM], _i, _j; \ int _l; \ \ GET_INDICES(index,cCounts,nDim); \ for (_i = _l = 0; _i < nDim; _i++) \ _l += _indices[_i]*pstrides[_i]; \ for (_i = 0; _i < nVerts; _i++) \ eltBuf[_i] = _l + bumps[_i]; \ elt = eltBuf; \ } \ } #define GET_INDICES(index,knts,n) \ { \ int _i, _j; \ _j = index; \ for (_i = (n-1); _i >= 0; _i--) \ { \ _indices[_i] = _j % knts[_i]; \ _j = _j / knts[_i]; \ } \ } static void SortBuf(float *buf, int nPts, int nDim) { int i, j, k, l; float max; float *b; b = buf; for (l = 0; l < nDim; l++, b++) { for (i = 0; i < nPts; i++) { max = b[i*nDim]; j = i; for (k = i+1; k < nPts; k++) if (b[k*nDim] > max) { max = b[k*nDim]; j = k; } if (i != j) SWAP(b[i*nDim], b[j*nDim]); } } } int tetraFaces[] = { 1, 2, 3, 2, 3, 0, 3, 0, 1, 0, 1, 2 }; int nTetraFaces = 4; int nTetraFaceVertices = 3; int triangleFaces[] = { 1, 2, 2, 0, 0, 1 }; int nTriangleFaces = 3; int nTriangleFaceVertices = 2; int quadFaces[] = { 0, 1, 2, 3, 0, 2, 1, 3, }; int nQuadFaces = 4; int nQuadFaceVertices = 2; int cubeFaces[] = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 4, 5, 2, 3, 6, 7, 0, 4, 2, 6, 1, 5, 3, 7, }; int nCubeFaces = 6; int nCubeFaceVertices = 4; static Error IPN_pass1(Pointer args) { int i, j, k, l; Field field; HashTable hash; Array cA, pA, nA; int nDim, nVerts; int *elements, *elt, eltBuf[16]; int *neighbors, *nPtr; float *points; int pCounts[MAXDIM]; float pOrigin[MAXDIM], pDeltas[MAXDIM*MAXDIM]; int cCounts[MAXDIM], nConnections; float buf[MAXDIM*8], *bufPtr; Object attr; char *str; int *table, nFaces, nFaceVerts; HashItem item; int nExternals; int pstrides[3]; int cstrides[3]; int bumps[32]; field = ((struct IPN_pass1_args *)args)->field; if (DXEmptyField(field)) return OK; attr = DXGetComponentAttribute(field, "connections", "element type"); if (! attr) { DXSetError(ERROR_MISSING_DATA, "element type attribute"); goto error; } if (DXGetObjectClass(attr) != CLASS_STRING) { DXSetError(ERROR_MISSING_DATA, "element type attribute"); goto error; } str = DXGetString((String)attr); if (! strcmp(str, "cubes")) { table = cubeFaces; nFaces = nCubeFaces; nFaceVerts = nCubeFaceVertices; } else if (! strcmp(str, "tetrahedra")) { table = tetraFaces; nFaces = nTetraFaces; nFaceVerts = nTetraFaceVertices; } else if (! strcmp(str, "triangles")) { table = triangleFaces; nFaces = nTriangleFaces; nFaceVerts = nTriangleFaceVertices; } else if (! strcmp(str, "quads")) { table = quadFaces; nFaces = nQuadFaces; nFaceVerts = nQuadFaceVertices; } else { DXSetError(ERROR_NOT_IMPLEMENTED, "superneighbors on %s", str); goto error; } hash = DXCreateHash(sizeof(HashItem), FaceHash, FaceCmp); if (! hash) goto error; pA = (Array)DXGetComponentValue(field, "positions"); cA = (Array)DXGetComponentValue(field, "connections"); if (! pA || ! cA) goto error; if (DXQueryGridPositions(pA, &nDim, pCounts, pOrigin, pDeltas)) { points = NULL; } else { DXGetArrayInfo(pA, NULL, NULL, NULL, NULL, &nDim); if (NULL == (points = (float *)DXGetArrayData(pA))) goto error; } DXGetArrayInfo(cA, &nConnections, NULL, NULL, NULL, &nVerts); if (DXQueryGridConnections(cA, NULL, cCounts)) { int incs[3]; Object attr; for (i = 0; i < nDim; i++) { pCounts[i] = cCounts[i]; cCounts[i] -= 1; } pstrides[nDim-1] = cstrides[nDim-1] = 1; for (i = nDim-2; i >= 0; i--) { cstrides[i] = cstrides[i+1] * cCounts[i+1]; pstrides[i] = pstrides[i+1] * pCounts[i+1]; } for (i = 0; i < (1 << nDim); i++) { bumps[i] = 0; for (j = 0; j < nDim; j++) if (i & (1 << j)) bumps[i] += pstrides[(nDim-1)-j]; } /* * If its a regular grid connections array, we have a warped regular * array. We need to create a neighbors array since the standard * interface won't. */ nA = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, nFaces); if (! nA) goto error; if (! DXSetComponentValue(field, "neighbors", (Object)nA)) { DXDelete((Object)nA); goto error; } attr = (Object)DXNewString("connections"); if (! attr) goto error; if (! DXSetComponentAttribute(field, "neighbors", "dep", attr)) goto error; if (! DXSetComponentAttribute(field, "neighbors", "ref", attr)) goto error; if (! DXSetComponentAttribute(field, "neighbors", "der", attr)) goto error; if (! DXAddArrayData(nA, 0, nConnections, NULL)) goto error; neighbors = (int *)DXGetArrayData(nA); /* * For each element, create its neighbors list. The incs array * accumulates the element indices. */ incs[0] = incs[1] = incs[2] = 0; nPtr = neighbors; for (i = 0; i < nConnections; i++) { /* * For each dimension in x -> z order, if its the first element * set its down neighbor to -1; otherwise to the element indexed * by the same indicies excepting the j-th entry, which is the * same - 1. Similarly, if is the last... */ for (j = 0; j < nDim; j++) { if (incs[j] == 0) *nPtr++ = -1; else { /* * Decrement that index and determine the offset of the * neighbor. Then restore the index. */ incs[j] -= 1; for (k = l = 0; k < nDim; k++) l += incs[k] * cstrides[k]; *nPtr++ = l; incs[j] += 1; } if (incs[j] == cCounts[j] - 1) *nPtr++ = -1; else { /* * Increment that index and determine the offset of the * neighbor. Then restore the index. */ incs[j] += 1; for (k = l = 0; k < nDim; k++) l += incs[k] * cstrides[k]; *nPtr++ = l; incs[j] -= 1; } } for (j = (nDim - 1); j >= 0; j--) { incs[j] ++; if (incs[j] == (cCounts[j])) { if (j == 0 && i != nConnections-1) { DXMessage("loop error"); } else { incs[j] = 0; } } else break; } } elements = NULL; elt = eltBuf; } else { if (NULL == (elements = (int *)DXGetArrayData(cA))) goto error; nA = DXNeighbors(field); if (! nA) { if (DXGetError() != ERROR_NONE) DXSetError(ERROR_INTERNAL, "DXNeighbors failed without setting error"); goto error; } if (NULL == (neighbors = (int *)DXGetArrayData(nA))) goto error; } for (i = 0; i < 3; i++) item.point[i] = 0.0; nPtr = neighbors; nExternals = 0; for (i = 0; i < nConnections; i++) { int jj; GET_ELEMENT(i); item.element = i; for (jj = 0; jj < nFaces; jj++, nPtr++) { if (*nPtr < 0) { *nPtr = -1; bufPtr = buf; for (k = 0; k < nFaceVerts; k++) { GET_POINT(elt[table[jj*nFaceVerts+k]], bufPtr); bufPtr += nDim; } SortBuf(buf, nFaceVerts, nDim); bufPtr = buf + nDim; for (k = 1; k < nFaceVerts; k++) for (l = 0; l < nDim; l++) buf[l] += *bufPtr++; for (k = 0; k < nDim; k++) item.point[k] = buf[k]; item.face = jj; if (! DXInsertHashElement(hash, (Element)&item)) goto error; nExternals ++; } } } *(((struct IPN_pass1_args *)args)->hPtr) = hash; return OK; error: if (hash) DXDestroyHash(hash); return ERROR; } static Error MinMaxBox(Field f, float *min, float *max) { float box[24], *b, fuzz; int i, j; if (! DXBoundingBox((Object)f, (Point *)box)) return ERROR; min[0] = min[1] = min[2] = DXD_MAX_FLOAT; max[0] = max[1] = max[2] = -DXD_MAX_FLOAT; b = box; for (i = 0; i < 8; i++) for (j = 0; j < 3; j++, b++) { if (*b < min[j]) min[j] = *b; if (*b > max[j]) max[j] = *b; } for (i = 0; i < 3; i++) { fuzz = (max[i] - min[i]) * 0.001; max[i] += fuzz; min[i] -= fuzz; } return OK; } static int BoxOverlap(float *m0, float *M0, float *m1, float *M1) { if (M1[0] < m0[0]) return 0; if (M1[1] < m0[1]) return 0; if (M1[2] < m0[2]) return 0; if (m1[0] > M0[0]) return 0; if (m1[1] > M0[1]) return 0; if (m1[2] > M0[2]) return 0; return 1; } #define BUFSIZE 16 #define FLUSHBUF \ { \ if (! DXAddArrayData(pA, aKnt, bKnt, (Pointer)exBuf)) \ goto error; \ aKnt += bKnt; \ bKnt = 0; \ } #define ADDEXTERNAL(field, element) \ { \ if (bKnt == BUFSIZE) \ FLUSHBUF; \ \ exBuf[bKnt<<1] = (int)field; \ exBuf[(bKnt<<1)+1] = element; \ bKnt ++; \ } static Error IPN_pass2(Pointer ptr) { Field *fieldList = ((struct IPN_pass2_args *)ptr)->fields; HashTable *hashList = ((struct IPN_pass2_args *)ptr)->hashes; int nPartitions = ((struct IPN_pass2_args *)ptr)->n; int myPartition = ((struct IPN_pass2_args *)ptr)->i; float myMin[3], myMax[3]; float hisMin[3], hisMax[3]; HashTable myHash, hisHash; Field myField, hisField; Array nA, pA = NULL, nnA = NULL; int *neighbors; HashItem *myItem, *hisItem; int nExternals; int exBuf[2*BUFSIZE]; int aKnt, bKnt; int nFaces, nElements; int i; myHash = hashList[myPartition]; if (! myHash) return OK; myField = fieldList[myPartition]; if (! MinMaxBox(myField, myMin, myMax)) goto error; nA = (Array)DXGetComponentValue(myField, "neighbors"); if (! nA) { DXSetError(ERROR_MISSING_DATA, "neighbors in pass2"); goto error; } DXGetArrayInfo(nA, &nElements, NULL, NULL, NULL, &nFaces); pA = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, 2); if (! pA) goto error; nnA = DXNewArray(TYPE_INT, CATEGORY_REAL, 1, nFaces); if (! nnA) goto error; if (! DXAddArrayData(nnA, 0, nElements, DXGetArrayData(nA))) goto error; neighbors = (int *)DXGetArrayData(nnA); if (! neighbors) goto error; if (! DXSetComponentValue(myField, "neighbors", (Object)nnA)) goto error; nnA = NULL; aKnt = bKnt = 0; ADDEXTERNAL(-1,-1); ADDEXTERNAL(-1,-1); for (i = 0; i < nPartitions; i++) if (i != myPartition) { hisField = fieldList[i]; hisHash = hashList[i]; if (! hisHash) continue; if (! MinMaxBox(hisField, hisMin, hisMax)) goto error; if (BoxOverlap(myMin, myMax, hisMin, hisMax)) { hisHash = hashList[i]; DXInitGetNextHashElement(myHash); while (NULL != (myItem=(HashItem *)DXGetNextHashElement(myHash))) if (NULL != (hisItem=(HashItem *)DXQueryHashElement(hisHash, (Element)myItem))) { neighbors[myItem->element*nFaces+myItem->face] = -(aKnt+bKnt); ADDEXTERNAL(i, hisItem->element); } } } FLUSHBUF; if (! DXSetComponentValue(myField, "partition neighbors", (Object)pA)) goto error; return OK; error: DXDelete((Object)pA); DXDelete((Object)nnA); return ERROR; }