void AggregateClusters(uint uParentLayer) { // number of cells in each grid cluster uint[] pClusterDims = mInfluenceTree.GetDecimations((int)uParentLayer); uint[] numCells = { mInfluenceTree[uParentLayer].GetNumCells(0), mInfluenceTree[uParentLayer].GetNumCells(1), mInfluenceTree[uParentLayer].GetNumCells(2) }; uint numXY = mInfluenceTree[uParentLayer].GetNumPoints(0) * mInfluenceTree[uParentLayer].GetNumPoints(1); // (Since this loop writes to each parent cell, it should readily parallelize without contention.) uint[] idxParent = new uint[3]; for (idxParent[2] = 0; idxParent[2] < numCells[2]; ++idxParent[2]) { uint offsetZ = idxParent[2] * numXY; for (idxParent[1] = 0; idxParent[1] < numCells[1]; ++idxParent[1]) { uint offsetYZ = idxParent[1] * mInfluenceTree[uParentLayer].GetNumPoints(0) + offsetZ; for (idxParent[0] = 0; idxParent[0] < numCells[0]; ++idxParent[0]) { // For each cell in the parent layer... uint offsetXYZ = idxParent[0] + offsetYZ; UniformGrid <Vorton> rChildLayer = mInfluenceTree[uParentLayer - 1]; VortonClusterAux vortAux = new VortonClusterAux(); uint[] clusterMinIndices = mInfluenceTree.GetChildClusterMinCornerIndex(pClusterDims, idxParent);; uint[] increment = { 0, 0, 0 }; uint numXchild = rChildLayer.GetNumPoints(0); uint numXYchild = numXchild * rChildLayer.GetNumPoints(1); // For each cell of child layer in this grid cluster... for (increment[2] = 0; increment[2] < pClusterDims[2]; ++increment[2]) { uint childOffsetZ = (clusterMinIndices[2] + increment[2]) * numXYchild; for (increment[1] = 0; increment[1] < pClusterDims[1]; ++increment[1]) { uint childOffsetYZ = (clusterMinIndices[1] + increment[1]) * numXchild + childOffsetZ; for (increment[0] = 0; increment[0] < pClusterDims[0]; ++increment[0]) { uint childOffsetXYZ = (clusterMinIndices[0] + increment[0]) + childOffsetYZ; Vorton rVortonChild = rChildLayer[childOffsetXYZ]; float vortMag = rVortonChild.vorticity.magnitude; // Aggregate vorton cluster from child layer into parent layer: mInfluenceTree[uParentLayer][offsetXYZ].position += rVortonChild.position * vortMag; mInfluenceTree[uParentLayer][offsetXYZ].vorticity += rVortonChild.vorticity; vortAux.mVortNormSum += vortMag; if (rVortonChild.radius != 0.0f) { mInfluenceTree[uParentLayer][offsetXYZ].radius = rVortonChild.radius; } } } } // Normalize weighted position sum to obtain center-of-vorticity. // (See analogous code in MakeBaseVortonGrid.) mInfluenceTree[uParentLayer][offsetXYZ].position /= vortAux.mVortNormSum; } } } }
/* * Create base layer of vorton influence tree. * * This is the leaf layer, where each grid cell corresponds(on average) to * a single vorton.Some cells might contain multiple vortons and some zero. * * Each cell effectively has a single "supervorton" which its parent layers * in the influence tree will in turn aggregate. * * This implementation of gridifying the base layer is NOT suitable * for Eulerian operations like approximating spatial derivatives * * of vorticity or solving a vector Poisson equation, because this * routine associates each vortex with a single corner point of the * grid cell that contains it. To create a grid for Eulerian calculations, * each vorton would contribute to all 8 corner points of the grid * cell that contains it. * * We could rewrite this to suit "Eulerian" operations, in which case * we would want to omit "size" and "position" since the grid would * * implicitly represent that information. That concern goes hand-in-hand * with the method used to compute velocity from vorticity. * * Ultimately we need to make sure theoretically conserved quantities behave as expected. * * This method assumes the influence tree skeleton has already been created, * and the leaf layer initialized to all "zeros", meaning it contains no vortons. */ public void MakeBaseVortonGrid() { int numVortons = mVortons.Count; UniformGrid <VortonClusterAux> ugAux = new UniformGrid <VortonClusterAux>(mInfluenceTree[0]); // Temporary auxilliary information used during aggregation. ugAux.Init(); // Compute preliminary vorticity grid. for (int uVorton = 0; uVorton < numVortons; ++uVorton) { // For each vorton in this simulation... Vector3 position = mVortons[uVorton].position; uint uOffset = mInfluenceTree[0].OffsetOfPosition(position); float vortMag = mVortons[uVorton].vorticity.magnitude; mInfluenceTree[0][uOffset].position += mVortons[uVorton].position * vortMag; // Compute weighted position -- to be normalized later. mInfluenceTree[0][uOffset].vorticity += mVortons[uVorton].vorticity; // Tally vorticity sum. mInfluenceTree[0][uOffset].radius = mVortons[uVorton].radius; // Assign volume element size. // OBSOLETE. See comments below: UpdateBoundingBox( rVortonAux.mMinCorner , rVortonAux.mMaxCorner , rVorton.mPosition ) ; ugAux[uOffset].mVortNormSum += vortMag; // Accumulate vorticity on the VortonClusterAux } // Post-process preliminary grid (VortonClusterAux); normalize center-of-vorticity and compute sizes, for each grid cell. uint[] num = { mInfluenceTree[0].GetNumPoints(0), mInfluenceTree[0].GetNumPoints(1), mInfluenceTree[0].GetNumPoints(2) }; uint numXY = num[0] * num[1]; uint[] idx = new uint[3]; for (idx[2] = 0; idx[2] < num[2]; ++idx[2]) { uint zShift = idx[2] * numXY; for (idx[1] = 0; idx[1] < num[1]; ++idx[1]) { uint yzShift = idx[1] * num[0] + zShift; for (idx[0] = 0; idx[0] < num[0]; ++idx[0]) { uint offset = idx[0] + yzShift; VortonClusterAux rVortonAux = ugAux[offset]; if (rVortonAux.mVortNormSum != float.Epsilon) { // This cell contains at least one vorton. // Normalize weighted position sum to obtain center-of-vorticity. mInfluenceTree[0][offset].position /= rVortonAux.mVortNormSum; } } } } }