/***********************************************************************/ /* 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 #include #include "_compute.h" /* Some concepts: * This probably belongs elsewhere, and will get moved, but here it is. * Definitions: * Heterogeneous Groups are Objects with both class and subClass CLASS_GROUP. * Homogeneous Groups are Groups whose members have the same metaType. * Parts (as elsewhere) are all fields and leaves. * Virtual Parts are all Objects that aren't heterogeneous groups and are not * members of homogeneous groups. * The Parents of a part is the closest ancestor in the group hierarchy that * is a virtual part. A part may be its own parent. * * Virtual Parts have a copy of the parse tree which contains type * information unique to that virtual part. * Parts have pointers to parent's parse trees. * * Execution: * The general model is that to execute a parse node, * result data space is allocated for each child parse node * those nodes are executed recursively * the operation represented by this node is performed * the temporary data space for children is freed, * the result is returned. * * For each virtual part, execute each child; * To execute a child (part): * Allocate a result array * Execute (part, parseTree, result); * if part is field * replace part->output."data" with result * else part is array * Allocate new array with result data into part->output * if part is a member of an group, insert part->output into group. * Free result * Both of the above routines may be executed in parallel. * The model should be that if there is more than one part, go parallel * building descriptors of a pointer to the part and a pointer to the parse * tree. Each node in the ObjStruct array has an appropriate "output" * field in which to insert the results. */ typedef struct { ObjStruct *os; PTreeNode *pt; } TaskArg; #define IS_CONTAINER_CLASS(x) (\ (x) == CLASS_GROUP || \ (x) == CLASS_XFORM || \ (x) == CLASS_SCREEN || \ (x) == CLASS_CLIPPED) static int Execute (Pointer ptr) { TaskArg *ta = (TaskArg *)ptr; ObjStruct *os = ta->os; PTreeNode *pt = ta->pt; Pointer result = NULL; InvalidComponentHandle invalid = NULL; int numBasic; int i; Array a = NULL; Pointer deltas; Error status = OK; PTreeNode *this; PTreeNode *next; int executionFinished = 0; #ifdef COMP_DEBUG DXDebug ("C", "TypeCheck (from ExecuteTask if parallel)"); #endif _dxfComputeInitExecution(); for (next = pt->args; next; ) { this = next; next = this->next; if (os->parseTree) _dxfComputeFreeTree(os->parseTree); if (_dxfComputeTypeCheck (this, os) == ERROR) { goto error; } this = os->parseTree; if (os->metaType.items == 0) { continue; } #ifdef COMP_DEBUG DXDebug ("C", "Execute Node (from Execute Task if parallel)"); #endif if (this->metaType.items != 0) { for (numBasic = 1, i = 0; i < this->metaType.rank; ++i) { numBasic *= this->metaType.shape[i]; } if (result) DXFree(result); result = DXAllocateLocalZero ( this->metaType.items * DXTypeSize (this->metaType.type) * DXCategorySize (this->metaType.category) * numBasic); if (result == NULL) { DXResetError(); result = DXAllocateZero ( this->metaType.items * DXTypeSize (this->metaType.type) * DXCategorySize (this->metaType.category) * numBasic); if (result == NULL) { goto error; } } if (invalid) { DXFreeInvalidComponentHandle(invalid); invalid = NULL; } status = _dxfComputeExecuteNode (this, os, result, &invalid); if (status == ERROR) { goto error; } } } _dxfComputeFinishExecution(); executionFinished = 1; if (os->metaType.items != 0) { if (this->metaType.items == 1 && os->metaType.items > 1) { a = (Array) DXNewConstantArrayV( os->metaType.items, result, this->metaType.type, this->metaType.category, this->metaType.rank, this->metaType.shape); if (a == NULL) { goto error; } } else { a = DXNewArrayV (this->metaType.type, this->metaType.category, this->metaType.rank, this->metaType.shape); if (a == NULL) { goto error; } if (DXAddArrayData (a, 0, os->metaType.items, result) == NULL) { goto error; } } if (os->class == CLASS_FIELD) { Object origData; int hadData; int hasPositions; Object attr; int hasDepComponent = 0; char *dep; origData = DXGetComponentValue((Field)os->output, "data"); hadData = origData != NULL; hasPositions = DXGetComponentValue((Field)os->output, "positions") != NULL; if (origData) { attr = DXGetAttribute (origData, "dep"); if (DXExtractString(attr, &dep)) hasDepComponent = DXGetComponentValue((Field)os->output, dep) != NULL; } else hasDepComponent = hasPositions; if (DXSetComponentValue ((Field)os->output, "data", (Object)a) == NULL) { goto error; } a = NULL; if (invalid != NULL) { if (hasDepComponent && DXSaveInvalidComponent((Field)os->output, invalid) == ERROR) { goto error; } DXFreeInvalidComponentHandle(invalid); invalid = NULL; } if (DXChangedComponentValues ((Field)os->output, "data") == NULL) { goto error; } if (!hadData && hasPositions) { if (DXSetComponentAttribute((Field)os->output, "data", "dep", (Object)DXNewString("positions")) == NULL) { goto error; } } } else { DXCopyAttributes((Object)a, os->output); os->output = (Object)a; } } DXFree(result); return (OK); error: if (!executionFinished) { _dxfComputeFinishExecution(); } DXDelete((Object)a); DXFree(result); DXFreeInvalidComponentHandle(invalid); return ERROR; } /* A routine to take a part and a parse tree, and execute it. */ static int ExecutePart (ObjStruct *inputStruct, PTreeNode *parseTree, int parallel) { TaskArg ta; #ifdef COMP_DEBUG DXDebug ("C", "ExecutePart (parallel = %d)", parallel); #endif ta.os = inputStruct; ta.pt = parseTree; if (parallel) { return (DXAddTask (Execute, (Pointer)&ta, sizeof (TaskArg), 1.0)); } else { return (Execute (&ta)); } } /* A routine to take a virtual-part (group), and execute it wrt its parse * tree. */ static int ExecuteVirtualPart (ObjStruct *inputStruct, PTreeNode *tree, int parallel) { ObjStruct *subStruct; #ifdef COMP_DEBUG DXDebug ("C", "ExecuteVirtualPart (parallel = %d)", parallel); #endif /* Execute each child */ if (!IS_CONTAINER_CLASS(inputStruct->class)) { if (ExecutePart (inputStruct, tree, parallel) != OK) return (ERROR); } else { subStruct = inputStruct->members; while (subStruct != NULL) { if (ExecuteVirtualPart (subStruct, tree, parallel) != OK) return (ERROR); subStruct = subStruct->next; } } return (OK); } /* A routine to take a node, and determine if it is a virtual-part ready for * execution, or recurse. */ static int ExecuteStruct (ObjStruct *inputStruct, PTreeNode *tree, int parallel) { ObjStruct *subStruct; #ifdef COMP_DEBUG DXDebug ("C", "ExecuteStruct (parallel = %d)", parallel); #endif switch (inputStruct->class) { case CLASS_XFORM: case CLASS_SCREEN: case CLASS_CLIPPED: case CLASS_GROUP: switch (inputStruct->subClass) { default: case CLASS_GROUP: subStruct = inputStruct->members; while (subStruct != NULL) { if (ExecuteStruct (subStruct, tree, parallel) == ERROR) return (ERROR); subStruct = subStruct->next; } break; case CLASS_SERIES: case CLASS_COMPOSITEFIELD: case CLASS_MULTIGRID: if (ExecuteVirtualPart (inputStruct, tree, parallel) == ERROR) return (ERROR); /* Set my new type */ break; } break; case CLASS_STRING: case CLASS_FIELD: case CLASS_ARRAY: if (ExecuteVirtualPart (inputStruct, tree, parallel) == ERROR) return (ERROR); break; default: DXSetError (ERROR_INTERNAL, "#10370", "input", "Array, Field, Group, Transform, Screen, or Clipped"); return (ERROR); } return (OK); } /* A routine to take a node, and determine if it is a virtual-part ready for * execution, or recurse. */ static int FixupStruct (ObjStruct *inputStruct) { ObjStruct *subStruct; int items; #ifdef COMP_DEBUG DXDebug ("C", "FixupStruct"); #endif if (inputStruct == NULL) return OK; switch(inputStruct->class) { case CLASS_GROUP: if (inputStruct->members != NULL) { subStruct = inputStruct->members; while (subStruct != NULL) { if (FixupStruct (subStruct) == ERROR) return (ERROR); subStruct = subStruct->next; } inputStruct->metaType = inputStruct->members->metaType; if (inputStruct->subClass != CLASS_GROUP) { subStruct = inputStruct->members; while (subStruct != NULL) { if (subStruct->class != CLASS_FIELD || subStruct->metaType.items != 0) { inputStruct->metaType = subStruct->metaType; break; } subStruct = subStruct->next; } if (subStruct && DXSetGroupTypeV ( (Group)inputStruct->output, inputStruct->metaType.type, inputStruct->metaType.category, inputStruct->metaType.rank, inputStruct->metaType.shape) == NULL) { return (ERROR); } } } break; case CLASS_XFORM: case CLASS_SCREEN: case CLASS_CLIPPED: if (FixupStruct (inputStruct->members) == ERROR) return (ERROR); break; default: items = inputStruct->metaType.items; inputStruct->metaType = inputStruct->parseTree->metaType; inputStruct->metaType.items = items; break; } return (OK); } /* A routine to take the root node and execute it. */ int _dxfComputeExecute (PTreeNode *tree, ObjStruct *inputStruct) { #ifdef COMP_DEBUG DXDebug ("C", "_ComputeExecute"); #endif if (DXProcessors(0) == 1) { #ifdef COMP_DEBUG DXDebug ("C", "Handle uniprocessor case."); #endif if (ExecuteStruct (inputStruct, tree, 0) == ERROR) return (ERROR); } else { #ifdef COMP_DEBUG DXDebug ("C", "Handle multiproc case."); #endif if (DXCreateTaskGroup() == ERROR) return (ERROR); if (ExecuteStruct (inputStruct, tree, 1) == ERROR) { DXAbortTaskGroup(); return (ERROR); } if (DXExecuteTaskGroup () == ERROR) return (ERROR); } return (FixupStruct (inputStruct)); }