예제 #1
0
    /*
     *  Compute velocity due to vortons, for a subset of points in a uniform grid
     *  izStart - starting value for z index
     *  izEnd - ending value for z index
     *
     *  This routine assumes CreateInfluenceTree has already executed,
     *  and that the velocity grid has been allocated.
     */
    void ComputeVelocityGridSlice(uint izStart, uint izEnd)
    {
        int numLayers = mInfluenceTree.GetDepth();

        Vector3 vMinCorner = mVelGrid.GetMinCorner();
        float   nudge      = 1.0f - 2.0f * global.GlobalVar.FLT_EPSILON;
        Vector3 vSpacing   = mVelGrid.GetCellSpacing() * nudge;

        uint[] dims = { mVelGrid.GetNumPoints(0)
                        , mVelGrid.GetNumPoints(1)
                        , mVelGrid.GetNumPoints(2) };
        uint   numXY = dims[0] * dims[1];

        uint[] idx = new uint[3];

        for (idx[2] = izStart; idx[2] < izEnd; ++idx[2])
        {   // For subset of z index values...
            Vector3 vPosition;
            // Compute the z-coordinate of the world-space position of this gridpoint.
            vPosition.z = vMinCorner.z + (float)(idx[2]) * vSpacing.z;
            // Precompute the z contribution to the offset into the velocity grid.
            uint offsetZ = idx[2] * numXY;
            for (idx[1] = 0; idx[1] < dims[1]; ++idx[1])
            {   // For every gridpoint along the y-axis...
                // Compute the y-coordinate of the world-space position of this gridpoint.
                vPosition.y = vMinCorner.y + (float)(idx[1]) * vSpacing.y;
                // Precompute the y contribution to the offset into the velocity grid.
                uint offsetYZ = idx[1] * dims[0] + offsetZ;
                for (idx[0] = 0; idx[0] < dims[0]; ++idx[0])
                {   // For every gridpoint along the x-axis...
                    // Compute the x-coordinate of the world-space position of this gridpoint.
                    vPosition.x = vMinCorner.x + (float)(idx[0]) * vSpacing.x;
                    // Compute the offset into the velocity grid.
                    uint offsetXYZ = idx[0] + offsetYZ;

                    // Compute the fluid flow velocity at this gridpoint, due to all vortons.
                    uint[] zeros = { 0, 0, 0 };    // Starter indices for recursive algorithm
                    mVelGrid[offsetXYZ] = ComputeVelocity(vPosition, zeros, numLayers - 1);
                }
            }
        }
    }
    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
        }
    }
예제 #3
0
    /*
     *  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
        }
    }