/***********************************************************************/ /* 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 #include static Object ObjectPartition(Object, int, int); /* default number of partitions if number of processors > 1 */ #define FACTOR(x) ((x-1) * 2) int m_Partition(Object *in, Object *out) { int maxnum, mincount; Object o; out[0] = NULL; if (!in[0]) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "input"); return ERROR; } if (in[1]) { if (!DXExtractInteger(in[1], &maxnum)) { DXSetError(ERROR_BAD_PARAMETER, "#10020", "number of partitions"); return ERROR; } if (maxnum <= 0) { DXSetError(ERROR_BAD_PARAMETER, "#10020", "number of partitions"); return ERROR; } } else { maxnum = DXProcessors(0); if (maxnum > 1) maxnum = FACTOR(maxnum); } if (in[2]) { if (!DXExtractInteger(in[2], &mincount)) { DXSetError(ERROR_BAD_PARAMETER, "#10030", "number of points"); return ERROR; } if (mincount < 0) { DXSetError(ERROR_BAD_PARAMETER, "#10030", "number of points"); return ERROR; } } else mincount = 1; if (maxnum == 1) out[0] = in[0]; else out[0] = ObjectPartition(in[0], maxnum, mincount); return(out[0] ? OK : ERROR); } static Error Pass1(Object, HashTable); static Object Pass2(Object, HashTable); static CompositeField MkPartitionTemplate(Field, int, int); static CompositeField CpPartitionTemplate(Field, CompositeField); static CompositeField CpPartitionTemplate_Reg(Field, CompositeField); static CompositeField CpPartitionTemplate_Irreg(Field, CompositeField); static int Cmp(Key, Key); static PseudoKey Hash(Key); #define MAXDIM 32 /* * Object-level interface for sharing partitioning among objects that share * positions and connections */ typedef struct { Object p; Object c; Field f; CompositeField template; int knt; int unpart; /* fields which return unpartitioned */ } HElement; static Object ObjectPartition(Object o, int n, int size) { HashTable hTable = NULL; HElement *elt; hTable = DXCreateHash(sizeof(HElement), Hash, Cmp); if (! hTable) goto error; /* * Pass1 finds each field contained in the input object (exclusive of * those alreay contained in the input) and accesses the hash table * keyed by the positions and connections array addresses. If no entry * is found then this pair is unique (so far) and an entry is created. * Otherwise, the hash table entry's counter field is incremented. */ if (! Pass1(o, hTable)) goto error; /* * Traverse the hash table partitioning each unique positions/connections * pair. If only one field referenced the pair, partition it directly. * Otherwise, create a partition template. */ DXInitGetNextHashElement(hTable); while ((elt = (HElement *)DXGetNextHashElement(hTable)) != NULL) { if (elt->knt == 1) elt->template = (CompositeField)DXPartition(elt->f, n, size); else elt->template = MkPartitionTemplate(elt->f, n, size); if (! elt->template) goto error; /* did partition actually do anything, or was the return from * partition the identical field we sent in? */ elt->unpart = ((Pointer)elt->template == (Pointer)elt->f); } /* * Pass2 copies the input object, replacing each field contained * therein (excepting those already contained by a composite field) * with a partitioned version thereof. */ o = Pass2(o, hTable); if (! o) goto error; /* * Need to delete any templates we created */ DXInitGetNextHashElement(hTable); while ((elt = (HElement *)DXGetNextHashElement(hTable)) != NULL) if (elt->knt > 1 && !elt->unpart) DXDelete((Object)elt->template); DXDestroyHash(hTable); if (! DXEndObject(o)) { DXDelete(o); goto error; } return o; error: DXDestroyHash(hTable); return ERROR; } static Error Pass1(Object o, HashTable hTable) { Class class; HElement helt, *hptr; Field f; if (! o) return OK; class = DXGetObjectClass(o); if (class == CLASS_GROUP) class = DXGetGroupClass((Group)o); switch(class) { case CLASS_COMPOSITEFIELD: break; case CLASS_SERIES: case CLASS_MULTIGRID: case CLASS_GROUP: { int i; Object c; i = 0; while ((c = DXGetEnumeratedMember((Group)o, i++, NULL)) != NULL) if (! Pass1(c, hTable)) goto error; break; } case CLASS_XFORM: { Object c; if (! DXGetXformInfo((Xform)o, &c, NULL)) goto error; if (! Pass1(c, hTable)) goto error; break; } case CLASS_SCREEN: { Object c; if (! DXGetScreenInfo((Screen)o, &c, NULL, NULL)) goto error; if (! Pass1(c, hTable)) goto error; break; } case CLASS_CLIPPED: { Object c0, c1; if (! DXGetClippedInfo((Clipped)o, &c0, &c1)) goto error; if (c0) if (! Pass1(c0, hTable)) goto error; if (c1) if (! Pass1(c1, hTable)) goto error; break; } case CLASS_FIELD: { f = (Field)o; if (DXEmptyField(f)) break; helt.p = DXGetComponentValue(f, "positions"); helt.c = DXGetComponentValue(f, "connections"); helt.f = f; helt.template = NULL; helt.knt = 1; if (!helt.p || !helt.c) break; hptr = (HElement *)DXQueryHashElement(hTable, (Key)&helt); if (hptr) { hptr->knt ++; break; } if (! DXInsertHashElement(hTable, (Element)&helt)) goto error; break; } default: break; } return OK; error: return ERROR; } static Object Pass2(Object o, HashTable hTable) { Class class; if (! o) return NULL; class = DXGetObjectClass(o); if (class == CLASS_GROUP) class = DXGetGroupClass((Group)o); switch(class) { /* * Excludes series and composite fields */ case CLASS_GROUP: { int i; Object c, cnew = NULL; Group g; char *name; g = (Group)DXCopy(o, COPY_ATTRIBUTES); if (! g) return NULL; i = 0; while ((c = DXGetEnumeratedMember((Group)o, i, &name)) != NULL) { cnew = Pass2(c, hTable); if (! cnew) { DXDelete((Object)g); return NULL; } if (name) { if (! DXSetMember(g, name, cnew)) { DXDelete((Object)g); if (cnew != c) DXDelete((Object)cnew); return NULL; } } else { if (! DXSetEnumeratedMember(g, i, cnew)) { DXDelete((Object)g); if (cnew != c) DXDelete((Object)cnew); return NULL; } } i++; } return (Object)g; } case CLASS_MULTIGRID: { int i; Object c, cnew = NULL; MultiGrid g; char *name; g = (MultiGrid)DXCopy(o, COPY_ATTRIBUTES); if (! g) return NULL; i = 0; while ((c = DXGetEnumeratedMember((Group)o, i, &name)) != NULL) { cnew = Pass2(c, hTable); if (! cnew) { DXDelete((Object)g); return NULL; } if (name) { if (! DXSetMember((Group)g, name, cnew)) { DXDelete((Object)g); if (cnew != c) DXDelete((Object)cnew); return NULL; } } else { if (! DXSetEnumeratedMember((Group)g, i, cnew)) { DXDelete((Object)g); if (cnew != c) DXDelete((Object)cnew); return NULL; } } i++; } return (Object)g; } case CLASS_SERIES: { int i; Object c, cnew = NULL; Series g; float pos; g = (Series)DXCopy(o, COPY_ATTRIBUTES); if (! g) return NULL; i = 0; while ((c = DXGetSeriesMember((Series)o, i, &pos)) != NULL) { cnew = Pass2(c, hTable); if (! cnew) { DXDelete((Object)g); return NULL; } if (! DXSetSeriesMember(g, i, pos, cnew)) { DXDelete((Object)g); if (c != cnew) DXDelete((Object)cnew); return NULL; } i++; } return (Object)g; } case CLASS_XFORM: { Object c, cnew = NULL; Matrix m; Xform x; if (! DXGetXformInfo((Xform)o, &c, &m)) return NULL; cnew = Pass2(c, hTable); if (!cnew) return NULL; x = DXNewXform(cnew, m); if (! x && c != cnew) DXDelete((Object)cnew); return (Object)x; } case CLASS_SCREEN: { Object c, cnew = NULL; int f, z; Screen s; if (! DXGetScreenInfo((Screen)o, &c, &f, &z)) return NULL; cnew = Pass2(c, hTable); if (!cnew) return NULL; s = DXNewScreen(cnew, f, z); if (! s && c != cnew) DXDelete((Object)cnew); return (Object)s; } case CLASS_CLIPPED: { Object c0, c1, c0new = NULL; Clipped c; if (! DXGetClippedInfo((Clipped)o, &c0, &c1)) return NULL; if (c0) { c0new = Pass2(c0, hTable); if (!c0new) return NULL; } c = DXNewClipped(c0new, c1); if (! c && c0 != c0new) DXDelete((Object)c0new); return (Object)c; } case CLASS_FIELD: { HElement helt, *hptr; CompositeField cf; if (DXEmptyField((Field)o)) return DXCopy(o, COPY_STRUCTURE); helt.p = DXGetComponentValue((Field)o, "positions"); helt.c = DXGetComponentValue((Field)o, "connections"); helt.knt = 1; if (!helt.p || !helt.c) return DXCopy(o, COPY_STRUCTURE); hptr = (HElement *)DXQueryHashElement(hTable, (Key)&helt); if (! hptr) { DXSetError(ERROR_INTERNAL, "ObjectPartition2: missing pos/con pair\n"); return NULL; } /* if this field wasn't actually partitioned (DXPartition * returned the input instead of a new composite field) * just return the original object here. */ if (hptr->unpart) return o; /* * If only a single field contained this connections/positions pair, * then we simply partitioned it. Otherwise, we created a partition * template. */ if (hptr->knt > 1) cf = CpPartitionTemplate((Field)o, hptr->template); else cf = hptr->template; if (cf == NULL) return NULL; return (Object)cf; } default: return o; } } #define MKDATATEMPLATE(f, oname, nname) \ { \ int cnt, i, *ptr; \ Array a = (Array)DXGetComponentValue(f, oname); \ \ DXGetArrayInfo(a, &cnt, NULL, NULL, NULL, NULL); \ \ a = DXNewArray(TYPE_INT, CATEGORY_REAL, 0, 0); \ \ if (! DXAddArrayData(a, 0, cnt, NULL)) \ goto error; \ \ ptr = (int *)DXGetArrayData(a); \ for (i = 0; i < cnt; i++) \ *ptr++ = i; \ \ if (! DXSetComponentValue(f, nname, (Object)a)) \ goto error; \ \ if (! DXSetComponentAttribute(f, nname, "dep", \ (Object)DXNewString(oname))) \ goto error; \ } static CompositeField MkPartitionTemplate(Field f, int n, int size) { Array array; Object attr; Field nf = NULL; CompositeField cf = NULL; nf = DXNewField(); if (! nf) goto error; array = (Array)DXGetComponentValue(f, "positions"); if (! array) goto error; DXSetComponentValue(nf, "positions", (Object)array); array = (Array)DXGetComponentValue(f, "connections"); if (! array) goto error; DXSetComponentValue(nf, "connections", (Object)array); attr = DXGetComponentAttribute(f, "connections", "element type"); if (! attr) goto error; DXSetComponentAttribute(nf, "connections", "element type", attr); attr = DXGetComponentAttribute(f, "connections", "ref"); if (! attr) goto error; DXSetComponentAttribute(nf, "connections", "ref", attr); DXSetComponentAttribute(nf, "positions", "dep", attr); if (! DXQueryGridConnections(array, NULL, NULL)) { MKDATATEMPLATE(nf, "positions", "prefs"); MKDATATEMPLATE(nf, "connections", "crefs"); } DXReference((Object)nf); cf = (CompositeField)DXPartition(nf, n, size); if ((Pointer)cf == (Pointer)nf) { DXDelete((Object)nf); return (CompositeField)f; /* it really is a field */ } DXDelete((Object)nf); return cf; error: DXDelete((Object)nf); return NULL; } static CompositeField CpPartitionTemplate(Field in, CompositeField template) { Array a = (Array)DXGetComponentValue(in, "connections"); /* * Two cases: regular connections, in which the partitioning template * information is implicit in the connections array, and irregular * connections, in which the partitioning template information is * explicit in the map arrays "prefs" and "crefs". */ if (a && DXQueryGridConnections(a, NULL, NULL)) return CpPartitionTemplate_Reg(in, template); else return CpPartitionTemplate_Irreg(in, template); } static CompositeField CpPartitionTemplate_Reg(Field in, CompositeField template) { int i; CompositeField out = NULL; Array a, dst = NULL; int ndim, inCCounts[MAXDIM], inPCounts[MAXDIM]; int inCStrides[MAXDIM], inPStrides[MAXDIM]; Field c, f = NULL; float pos; Pointer o = NULL, d = NULL; /* * We will be copying data out of a regular grid. Need information * regarding the input grid. */ a = (Array)DXGetComponentValue(in, "connections"); if (! a) goto error; if (! DXQueryGridConnections(a, &ndim, inPCounts)) goto error; for (i = 0; i < ndim; i++) inCCounts[i] = inPCounts[i] - 1; inPStrides[ndim-1] = 1; inCStrides[ndim-1] = 1; for (i = ndim-2; i >= 0; i--) { inPStrides[i] = inPCounts[i+1]*inPStrides[i+1]; inCStrides[i] = inCCounts[i+1]*inCStrides[i+1]; } /* * Output structure */ out = DXNewCompositeField(); if (! out) goto error; i = 0; while((c = (Field)DXGetEnumeratedMember((Group)template, i++, NULL)) != NULL) { int outPCounts[MAXDIM], outCCounts[MAXDIM], offset[MAXDIM]; int outPStrides[MAXDIM], outCStrides[MAXDIM]; char *name; int j, np, nc; Array cArray, src; /* * Look at the connections component of the partition member * to determine the part of the input field that whis partition * member represents. */ cArray = (Array)DXGetComponentValue(c, "connections"); if (! cArray) goto error; if (! DXQueryGridConnections(cArray, NULL, outPCounts)) goto error; np = nc = 1; for (j = 0; j < ndim; j++) { outCCounts[j] = outPCounts[j] - 1; np *= outPCounts[j]; nc *= outCCounts[j]; } outPStrides[ndim-1] = 1; outCStrides[ndim-1] = 1; for (j = ndim-2; j >= 0; j--) { outPStrides[j] = outPCounts[j+1]*outPStrides[j+1]; outCStrides[j] = outCCounts[j+1]*outCStrides[j+1]; } if (! DXGetMeshOffsets((MeshArray)cArray, offset)) goto error; f = (Field)DXCopy((Object)in, COPY_STRUCTURE); if (! f) goto error; j = 0; while (NULL != (src=(Array)DXGetEnumeratedComponentValue(in, j++, &name))) { Object attr; int size, n; byte *srcData, *dstData; int k; int *inCounts, *inStrides, *outCounts, *outStrides; Type t; Category cat; int r, s[MAXDIM]; /* * If the component exists in the template, use it. Otherwise, * carve the necessary portion out of the corresponding component * of the input array. */ dst = (Array)DXGetComponentValue(c, name); if (dst) goto dst_done; /* * Select appropriate grid parameters depending on the * component's dependency. */ attr = (Object)DXGetComponentAttribute(in, name, "dep"); if (! attr) continue; if (!strcmp(DXGetString((String)attr), "positions")) { inStrides = inPStrides; outStrides = outPStrides; inCounts = inPCounts; outCounts = outPCounts; n = np; } else { inStrides = inCStrides; outStrides = outCStrides; inCounts = inCCounts; outCounts = outCCounts; n = nc; } DXGetArrayInfo(src, NULL, &t, &cat, &r, s); size = DXGetItemSize(src); /* * If the input component is constant regular, then * produce an appropriately sized constant regular * partition component. */ if (DXQueryConstantArray(src, NULL, NULL)) { dst = (Array)DXNewConstantArrayV(n, DXGetConstantArrayData(src), t, cat, r, s); if (!dst) goto error; else goto dst_done; } /* * OK. Its a non-constant array that doesn't appear in the * template. Create a new array and copy in the relevant portions. */ dst = DXNewArrayV(t, cat, r, s); if (! dst) goto error; if (! DXAddArrayData(dst, 0, n, NULL)) goto error; srcData = (byte *)DXGetArrayData(src); dstData = (byte *)DXGetArrayData(dst); for (k = 0; k < ndim; k++) srcData += offset[k]*inStrides[k]*size; _dxfPermute(ndim, dstData, outStrides, outCounts, size, srcData, inStrides); dst_done: DXCopyAttributes((Object)dst, (Object)src); DXSetComponentValue(f, name, (Object)dst); dst = NULL; } DXSetMember((Group)out, NULL, (Object)f); f = NULL; } return out; error: DXFree(d); DXFree(o); DXDelete((Object)dst); DXDelete((Object)f); DXDelete((Object)out); return NULL; } static CompositeField CpPartitionTemplate_Irreg(Field in, CompositeField template) { int i; CompositeField out = NULL; Field c; Field f = NULL; Array dst = NULL; Pointer d = NULL, o = NULL; out = DXNewCompositeField(); if (! out) goto error; i = 0; while((c = (Field)DXGetEnumeratedMember((Group)template, i++, NULL)) != NULL) { Array pRefArray = (Array)DXGetComponentValue(c, "prefs"); Array cRefArray = (Array)DXGetComponentValue(c, "crefs"); Array src; int *pRefs, *cRefs; int np, nc; int psz, csz; char *name; int j; f = (Field)DXCopy((Object)in, COPY_STRUCTURE); if (! f) goto error; DXGetArrayInfo(pRefArray, &np, NULL, NULL, NULL, NULL); DXGetArrayInfo(cRefArray, &nc, NULL, NULL, NULL, NULL); psz = DXGetItemSize(pRefArray); csz = DXGetItemSize(cRefArray); pRefs = (int *)DXGetArrayData(pRefArray); cRefs = (int *)DXGetArrayData(cRefArray); j = 0; while (NULL != (src=(Array)DXGetEnumeratedComponentValue(in, j++, &name))) { Object attr; int *refs, size, n; byte *srcData, *dstData; int k; Type t; Category cat; int r, s[MAXDIM]; /* * If the component exists in the template, use it. Otherwise, * carve the necessary portion out of the corresponding component * of the input array. */ dst = (Array)DXGetComponentValue(c, name); if (dst) goto dst_done; if (! strcmp(name, "neighbors") || DXGetComponentAttribute(in, name, "der")) { DXDeleteComponent(f, name); continue; } if (DXGetComponentAttribute(in, name, "ref")) { DXWarning("component %s contains references and cannot %s\n" "partition. It will be deleted.\n", name); DXDeleteComponent(f, name); continue; } /* * Select appropriate grid parameters depending on the * component's dependency. */ attr = (Object)DXGetComponentAttribute(in, name, "dep"); if (! attr) continue; if (!strcmp(DXGetString((String)attr), "positions")) { refs = pRefs; n = np; size = psz; } else { refs = cRefs; n = nc; size = csz; } DXGetArrayInfo(src, NULL, &t, &cat, &r, s); size = DXGetItemSize(src); /* * If the input component is constant regular, then * produce an appropriately sized constant regular * partition component. */ if (DXQueryConstantArray(src, NULL, NULL)) { dst = (Array)DXNewConstantArrayV(n, DXGetConstantArrayData(src), t, cat, r, s); if (!dst) goto error; else goto dst_done; } /* * OK. Its a non-constant array that doesn't appear in the * template. Create a new array and copy in the relevant portions. */ dst = DXNewArrayV(t, cat, r, s); if (! dst) goto error; if (! DXAddArrayData(dst, 0, n, NULL)) goto error; srcData = (byte *)DXGetArrayData(src); dstData = (byte *)DXGetArrayData(dst); for (k = 0; k < n; k++) { memcpy(dstData, srcData+size*(*refs), size); dstData += size; refs ++; } dst_done: if (! DXCopyAttributes((Object)dst, (Object)src)) goto error; if (! DXSetComponentValue(f, name, (Object)dst)) goto error; dst = NULL; } if (! DXSetMember((Group)out, NULL, (Object)f)) goto error; f = NULL; } return out; error: DXFree(d); DXFree(o); DXDelete((Object)dst); DXDelete((Object)f); DXDelete((Object)out); return NULL; } static int Cmp(Key k0, Key k1) { HElement *h0 = (HElement *)k0; HElement *h1 = (HElement *)k1; return ! ((h0->p == h1->p) && (h0->c == h1->c)); } static PseudoKey Hash(Key k) { long p; HElement *h = (HElement *)k; p = (((long)h->p) ^ (((long)h->c) << 12)) >> 2; return (PseudoKey)p; }