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; } } } }
/* * Precompute the total number of layers this nested grid will contain * src - UniformGrid upon which this NestedGrid is based. */ int PrecomputeNumLayers(UniformGrid <ItemT> src) { int numLayers = 1; // Tally src layer. uint[] numPoints = new uint[3]; numPoints[0] = src.GetNumPoints(0); numPoints[1] = src.GetNumPoints(1); numPoints[2] = src.GetNumPoints(2); uint size = numPoints[0] * numPoints[1] * numPoints[2]; while (size > 8 /* a cell has 8 corners */) { // Layer has more than 1 cell. ++numLayers; // Decimate number of cells (where #cells = #points-1): numPoints[0] = (uint)Mathf.Max((float)(numPoints[0] - 1) / 2, 1) + 1; numPoints[1] = (uint)Mathf.Max((float)(numPoints[1] - 1) / 2, 1) + 1; numPoints[2] = (uint)Mathf.Max((float)(numPoints[2] - 1) / 2, 1) + 1; size = numPoints[0] * numPoints[1] * numPoints[2]; } return(numLayers); }
/* * Compute velocity due to vortons, for every point in a uniform grid * This routine assumes CreateInfluenceTree has already executed. */ void ComputeVelocityGrid() { mVelGrid.Clear(); // Clear any stale velocity information mVelGrid.CopyShape(mInfluenceTree[0]); // Use same shape as base vorticity grid. (Note: could differ if you want.) mVelGrid.Init(); // Reserve memory for velocity grid. uint numZ = mVelGrid.GetNumPoints(2); if (mUseMultithreads) { // Estimate grain size based on size of problem and number of processors. int grainSize = (int)Mathf.Max(1, numZ / numberOfProcessors); List <ManualResetEvent> handles = new List <ManualResetEvent>(); for (var i = 0; i < numberOfProcessors; i++) { ManualResetEvent handle = new ManualResetEvent(false); handles.Add(handle); // Send the custom object to the threaded method. ThreadInfo threadInfo = new ThreadInfo(); threadInfo.begin = i * grainSize; threadInfo.end = (i + 1) * grainSize; threadInfo.timeStep = 0; threadInfo.vortonSim = this; threadInfo.handle = handle; WaitCallback callBack = new WaitCallback(ComputeVelocityGridSliceThreaded); Nyahoon.ThreadPool.QueueUserWorkItem(callBack, threadInfo); } WaitHandle.WaitAll(handles.ToArray()); } else { ComputeVelocityGridSlice(0, numZ); } }
public static void ComputeJacobian(ref UniformGrid <Matrix3x3> jacobian, UniformGrid <Vector> vec) { Vector3 spacing = vec.GetCellSpacing(); // Avoid divide-by-zero when z size is effectively 0 (for 2D domains) Vector3 reciprocalSpacing = new Vector3(1.0f / spacing.x, 1.0f / spacing.y, spacing.z > float.Epsilon ? 1.0f / spacing.z : 0.0f); Vector3 halfReciprocalSpacing = (0.5f * reciprocalSpacing); uint[] dims = { vec.GetNumPoints(0), vec.GetNumPoints(1), vec.GetNumPoints(2) }; uint[] dimsMinus1 = { vec.GetNumPoints(0) - 1, vec.GetNumPoints(1) - 1, vec.GetNumPoints(2) - 1 }; uint numXY = dims[0] * dims[1]; uint[] index = new uint[3]; // Compute derivatives for interior (i.e. away from boundaries). for (index[2] = 1; index[2] < dimsMinus1[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 1; index[1] < dimsMinus1[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 1; index[0] < dimsMinus1[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; Matrix3x3 rMatrix = jacobian[offsetX0Y0Z0]; /* Compute d/dx */ rMatrix.x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; /* Compute d/dy */ rMatrix.y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; /* Compute d/dz */ rMatrix.z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } #region boundariesDerivatives // Compute derivatives for boundaries: 6 faces of box. ------------------------------------------------------------ // In some situations, these macros compute extraneous data. // A tiny bit more efficiency could be squeezed from this routine, // but it turns out to be well under 1% of the total expense. // Compute derivatives for -X boundary. index[0] = 0; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for -Y boundary. index[1] = 0; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for -Z boundary. index[2] = 0; { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +X boundary. index[0] = dimsMinus1[0]; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +Y boundary. index[1] = dimsMinus1[1]; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +Z boundary. index[2] = dimsMinus1[2]; { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } #endregion } }
/* * Diffuse vorticity using a particle strength exchange method. * * This routine partitions space into cells using the same grid * as the "base vorton" grid. Each vorton gets assigned to the * cell that contains it. Then, each vorton exchanges some * of its vorticity with its neighbors in adjacent cells. * * This routine makes some simplifying assumptions to speed execution: * * - Distance does not influence the amount of vorticity exchanged, * except in as much as only vortons within a certain region of * each other exchange vorticity. This amounts to saying our kernel, * eta, is a top-hat function. * * - Theoretically, if an adjacent cell contains no vortons * then this simulation should generate vorticity within * that cell, e.g. by creating a new vorton in the adjacent cell. * * - This simulation reduces the vorticity of each vorton, alleging * that this vorticity is dissipated analogously to how energy * dissipates at Kolmogorov microscales. This treatment is not * realistic but it retains qualitative characteristics that we * want, e.g. that the flow dissipates at a rate related to viscosity. * Dissipation in real flows is a more complicated phenomenon. * * see Degond & Mas-Gallic (1989): The weighted particle method for * convection-diffusion equations, part 1: the case of an isotropic viscosity. * Math. Comput., v. 53, n. 188, pp. 485-507, October. * * timeStep - amount of time by which to advance simulation * * This routine assumes CreateInfluenceTree has already executed. * */ void DiffuseVorticityPSE(float timeStep) { // Phase 1: Partition vortons // Create a spatial partition for the vortons. // Each cell contains a dynamic array of integers // whose values are offsets into mVortons. UniformGrid <IntList> ugVortRef = new UniformGrid <IntList>(mInfluenceTree[0]); ugVortRef.Init(); int numVortons = mVortons.Count; for (int offset = 0 /* Start at 0th vorton */; offset < numVortons; ++offset) { // For each vorton... // Insert the vorton's offset into the spatial partition. ugVortRef[mVortons[offset].position].list.Add(offset); } // Phase 2: Exchange vorticity with nearest neighbors uint nx = ugVortRef.GetNumPoints(0); uint nxm1 = nx - 1; uint ny = ugVortRef.GetNumPoints(1); uint nym1 = ny - 1; uint nxy = nx * ny; uint nz = ugVortRef.GetNumPoints(2); uint nzm1 = nz - 1; uint[] idx = new uint[3]; for (idx[2] = 0; idx[2] < nzm1; ++idx[2]) { // For all points along z except the last... uint offsetZ0 = idx[2] * nxy; uint offsetZp = (idx[2] + 1) * nxy; for (idx[1] = 0; idx[1] < nym1; ++idx[1]) { // For all points along y except the last... uint offsetY0Z0 = idx[1] * nx + offsetZ0; uint offsetYpZ0 = (idx[1] + 1) * nx + offsetZ0; uint offsetY0Zp = idx[1] * nx + offsetZp; for (idx[0] = 0; idx[0] < nxm1; ++idx[0]) { // For all points along x except the last... uint offsetX0Y0Z0 = idx[0] + offsetY0Z0; for (int ivHere = 0; ivHere < ugVortRef[offsetX0Y0Z0].list.Count; ++ivHere) { // For each vorton in this gridcell... int rVortIdxHere = ugVortRef[offsetX0Y0Z0].list[ivHere]; Vorton rVortonHere = mVortons[rVortIdxHere]; Vector3 rVorticityHere = rVortonHere.vorticity; // Diffuse vorticity with other vortons in this same cell: for (int ivThere = ivHere + 1; ivThere < ugVortRef[offsetX0Y0Z0].list.Count; ++ivThere) { // For each OTHER vorton within this same cell... int rVortIdxThere = ugVortRef[offsetX0Y0Z0].list[ivThere]; Vorton rVortonThere = mVortons[rVortIdxThere]; Vector3 rVorticityThere = rVortonThere.vorticity; Vector3 vortDiff = rVorticityHere - rVorticityThere; Vector3 exchange = 2.0f * mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles. mVortons[rVortIdxHere].vorticity -= exchange; // Make "here" vorticity a little closer to "there". mVortons[rVortIdxThere].vorticity += exchange; // Make "there" vorticity a little closer to "here". } // Diffuse vorticity with vortons in adjacent cells: { uint offsetXpY0Z0 = idx[0] + 1 + offsetY0Z0; // offset of adjacent cell in +X direction for (int ivThere = 0; ivThere < ugVortRef[offsetXpY0Z0].list.Count; ++ivThere) { // For each vorton in the adjacent cell in +X direction... int rVortIdxThere = ugVortRef[offsetXpY0Z0].list[ivThere]; Vorton rVortonThere = mVortons[rVortIdxThere]; Vector3 rVorticityThere = rVortonThere.vorticity; Vector3 vortDiff = rVorticityHere - rVorticityThere; Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles. mVortons[rVortIdxHere].vorticity -= exchange; // Make "here" vorticity a little closer to "there". mVortons[rVortIdxThere].vorticity += exchange; // Make "there" vorticity a little closer to "here". } } { uint offsetX0YpZ0 = idx[0] + offsetYpZ0; // offset of adjacent cell in +Y direction for (int ivThere = 0; ivThere < ugVortRef[offsetX0YpZ0].list.Count; ++ivThere) { // For each vorton in the adjacent cell in +Y direction... int rVortIdxThere = ugVortRef[offsetX0YpZ0].list[ivThere]; Vorton rVortonThere = mVortons[rVortIdxThere]; Vector3 rVorticityThere = rVortonThere.vorticity; Vector3 vortDiff = rVorticityHere - rVorticityThere; Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles. mVortons[rVortIdxHere].vorticity -= exchange; // Make "here" vorticity a little closer to "there". mVortons[rVortIdxThere].vorticity += exchange; // Make "there" vorticity a little closer to "here". } } { uint offsetX0Y0Zp = idx[0] + offsetY0Zp; // offset of adjacent cell in +Z direction for (int ivThere = 0; ivThere < ugVortRef[offsetX0Y0Zp].list.Count; ++ivThere) { // For each vorton in the adjacent cell in +Z direction... int rVortIdxThere = ugVortRef[offsetX0Y0Zp].list[ivThere]; Vorton rVortonThere = mVortons[rVortIdxThere]; Vector3 rVorticityThere = rVortonThere.vorticity; Vector3 vortDiff = rVorticityHere - rVorticityThere; Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles. mVortons[rVortIdxHere].vorticity -= exchange; // Make "here" vorticity a little closer to "there". mVortons[rVortIdxThere].vorticity += exchange; // Make "there" vorticity a little closer to "here". } } // Dissipate vorticity. See notes in header comment. mVortons[rVortIdxHere].vorticity -= mViscosity * timeStep * mVortons[rVortIdxHere].vorticity; // Reduce "here" vorticity. } } } } }
/* * Compute velocity at a given point in space, due to influence of vortons * * vPosition - point in space whose velocity to evaluate * indices - indices of cell to visit in the given layer * iLayer - which layer to process * * returns velocity at vPosition, due to influence of vortons * This is a recursive algorithm with time complexity O(log(N)). * The outermost caller should pass in mInfluenceTree.GetDepth(). * */ Vector ComputeVelocity(Vector3 vPosition, uint[] indices, int iLayer) { Vector velocityAccumulator = new Vector(); UniformGrid <Vorton> rChildLayer = mInfluenceTree[(uint)iLayer - 1]; uint[] pClusterDims = mInfluenceTree.GetDecimations(iLayer); uint[] clusterMinIndices = mInfluenceTree.GetChildClusterMinCornerIndex(pClusterDims, indices); Vector3 vGridMinCorner = rChildLayer.GetMinCorner(); Vector3 vSpacing = rChildLayer.GetCellSpacing(); uint[] increment = new uint[3]; uint numXchild = rChildLayer.GetNumPoints(0); uint numXYchild = numXchild * rChildLayer.GetNumPoints(1); // The larger this is, the more accurate (and slower) the evaluation. // Reasonable values lie in [0.00001,4.0]. // Setting this to 0 leads to very bad errors, but values greater than (tiny) lead to drastic improvements. // Changes in margin have a quantized effect since they effectively indicate how many additional // cluster subdivisions to visit. float marginFactor = 0.0001f; // 0.4f ; // ship with this number: 0.0001f ; test with 0.4 // When domain is 2D in XY plane, min.z==max.z so vPos.z test below would fail unless margin.z!=0. Vector3 margin = marginFactor * vSpacing + (0.0f == vSpacing.z ? new Vector3(0, 0, float.Epsilon) : Vector3.zero); // For each cell of child layer in this grid cluster... for (increment[2] = 0; increment[2] < pClusterDims[2]; ++increment[2]) { uint[] idxChild = new uint[3]; idxChild[2] = clusterMinIndices[2] + increment[2]; Vector3 vCellMinCorner, vCellMaxCorner; vCellMinCorner.z = vGridMinCorner.z + (float)(idxChild[2]) * vSpacing.z; vCellMaxCorner.z = vGridMinCorner.z + (float)(idxChild[2] + 1) * vSpacing.z; uint offsetZ = idxChild[2] * numXYchild; for (increment[1] = 0; increment[1] < pClusterDims[1]; ++increment[1]) { idxChild[1] = clusterMinIndices[1] + increment[1]; vCellMinCorner.y = vGridMinCorner.y + (float)(idxChild[1]) * vSpacing.y; vCellMaxCorner.y = vGridMinCorner.y + (float)(idxChild[1] + 1) * vSpacing.y; uint offsetYZ = idxChild[1] * numXchild + offsetZ; for (increment[0] = 0; increment[0] < pClusterDims[0]; ++increment[0]) { idxChild[0] = clusterMinIndices[0] + increment[0]; vCellMinCorner.x = vGridMinCorner.x + (float)(idxChild[0]) * vSpacing.x; vCellMaxCorner.x = vGridMinCorner.x + (float)(idxChild[0] + 1) * vSpacing.x; if ( (iLayer > 1) && (vPosition.x >= vCellMinCorner.x - margin.x) && (vPosition.y >= vCellMinCorner.y - margin.y) && (vPosition.z >= vCellMinCorner.z - margin.z) && (vPosition.x < vCellMaxCorner.x + margin.x) && (vPosition.y < vCellMaxCorner.y + margin.y) && (vPosition.z < vCellMaxCorner.z + margin.z) ) { // Test position is inside childCell and currentLayer > 0... // Recurse child layer. Vector upVelocicy = ComputeVelocity(vPosition, idxChild, iLayer - 1); velocityAccumulator += upVelocicy; } else { // Test position is outside childCell, or reached leaf node. // Compute velocity induced by cell at corner point x. // Accumulate influence, storing in velocityAccumulator. uint offsetXYZ = idxChild[0] + offsetYZ; // Add velocity due to this vorton to the accumulator rChildLayer[offsetXYZ].AccumulateVelocity(ref velocityAccumulator, vPosition); } } } } return(velocityAccumulator); }
public static void ComputeJacobian(ref UniformGrid<Matrix3x3> jacobian, UniformGrid<Vector> vec) { Vector3 spacing = vec.GetCellSpacing(); // Avoid divide-by-zero when z size is effectively 0 (for 2D domains) Vector3 reciprocalSpacing = new Vector3(1.0f / spacing.x , 1.0f / spacing.y, spacing.z > float.Epsilon ? 1.0f / spacing.z : 0.0f ) ; Vector3 halfReciprocalSpacing = (0.5f * reciprocalSpacing) ; uint[] dims = { vec.GetNumPoints(0), vec.GetNumPoints(1), vec.GetNumPoints(2) }; uint[] dimsMinus1 = { vec.GetNumPoints(0) - 1, vec.GetNumPoints(1) - 1, vec.GetNumPoints(2) - 1 }; uint numXY = dims[0] * dims[1]; uint[] index = new uint[3]; // Compute derivatives for interior (i.e. away from boundaries). for (index[2] = 1; index[2] < dimsMinus1[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 1; index[1] < dimsMinus1[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 1; index[0] < dimsMinus1[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; Matrix3x3 rMatrix = jacobian[offsetX0Y0Z0]; /* Compute d/dx */ rMatrix.x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; /* Compute d/dy */ rMatrix.y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; /* Compute d/dz */ rMatrix.z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } #region boundariesDerivatives // Compute derivatives for boundaries: 6 faces of box. ------------------------------------------------------------ // In some situations, these macros compute extraneous data. // A tiny bit more efficiency could be squeezed from this routine, // but it turns out to be well under 1% of the total expense. // Compute derivatives for -X boundary. index[0] = 0; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for -Y boundary. index[1] = 0; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for -Z boundary. index[2] = 0; { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +X boundary. index[0] = dimsMinus1[0]; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +Y boundary. index[1] = dimsMinus1[1]; for (index[2] = 0; index[2] < dims[2]; ++index[2]) { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } } // Compute derivatives for +Z boundary. index[2] = dimsMinus1[2]; { //ASSIGN_Z_OFFSETS uint offsetZM = numXY * (index[2] - 1); uint offsetZ0 = numXY * index[2]; uint offsetZP = numXY * (index[2] + 1); for (index[1] = 0; index[1] < dims[1]; ++index[1]) { //ASSIGN_YZ_OFFSETS uint offsetYMZ0 = dims[0] * (index[1] - 1) + offsetZ0; uint offsetY0Z0 = dims[0] * index[1] + offsetZ0; uint offsetYPZ0 = dims[0] * (index[1] + 1) + offsetZ0; uint offsetY0ZM = dims[0] * index[1] + offsetZM; uint offsetY0ZP = dims[0] * index[1] + offsetZP; for (index[0] = 0; index[0] < dims[0]; ++index[0]) { //ASSIGN_XYZ_OFFSETS uint offsetX0Y0Z0 = index[0] + offsetY0Z0; uint offsetXMY0Z0 = index[0] - 1 + offsetY0Z0; uint offsetXPY0Z0 = index[0] + 1 + offsetY0Z0; uint offsetX0YMZ0 = index[0] + offsetYMZ0; uint offsetX0YPZ0 = index[0] + offsetYPZ0; uint offsetX0Y0ZM = index[0] + offsetY0ZM; uint offsetX0Y0ZP = index[0] + offsetY0ZP; //COMPUTE_FINITE_DIFF if (index[0] == 0) { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.x; } else if (index[0] == dimsMinus1[0]) { jacobian[offsetX0Y0Z0].x = (vec[offsetX0Y0Z0].v - vec[offsetXMY0Z0].v) * reciprocalSpacing.x; } else { jacobian[offsetX0Y0Z0].x = (vec[offsetXPY0Z0].v - vec[offsetXMY0Z0].v) * halfReciprocalSpacing.x; } if (index[1] == 0) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.y; } else if (index[1] == dimsMinus1[1]) { jacobian[offsetX0Y0Z0].y = (vec[offsetX0Y0Z0].v - vec[offsetX0YMZ0].v) * reciprocalSpacing.y; } else { jacobian[offsetX0Y0Z0].y = (vec[offsetX0YPZ0].v - vec[offsetX0YMZ0].v) * halfReciprocalSpacing.y; } if (index[2] == 0) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0Z0].v) * reciprocalSpacing.z; } else if (index[2] == dimsMinus1[2]) { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0Z0].v - vec[offsetX0Y0ZM].v) * reciprocalSpacing.z; } else { jacobian[offsetX0Y0Z0].z = (vec[offsetX0Y0ZP].v - vec[offsetX0Y0ZM].v) * halfReciprocalSpacing.z; } } } #endregion } }