Esempio n. 1
0
        private void Advect(double[] dest, double[] src, double[] xVelocity, double[] yVelocity, SetBoundsType boundType, double dt)
        {
            for (int y = 1; y < _ySize - 1; y++)
            {
                int yIndex = y * _xSize;
                for (int x = 1; x < _xSize - 1; x++)
                {
                    int k = x + yIndex;

                    if (_blocked[k])
                    {
                        continue;
                    }

                    //Reverse velocity, since we are interpolating backwards
                    //xSrc and ySrc is the position of the source density.
                    double xSrc = x - dt * xVelocity[k];
                    double ySrc = y - dt * yVelocity[k];

                    if (xSrc < 0.5) { xSrc = 0.5; }
                    if (xSrc > _xSize - 1.5) { xSrc = _xSize - 1.5; }
                    int xi0 = (int)xSrc;
                    int xi1 = xi0 + 1;

                    if (ySrc < 0.5) { ySrc = 0.5; }
                    if (ySrc > _ySize - 1.5) { ySrc = _ySize - 1.5; }
                    int yi0 = (int)ySrc;
                    int yi1 = yi0 + 1;

                    //Linear interpolation factors. Ex: 0.6 and 0.4
                    double xProp1 = xSrc - xi0;
                    double xProp0 = 1d - xProp1;
                    double yProp1 = ySrc - yi0;
                    double yProp0 = 1d - yProp1;

                    dest[k] =
                        xProp0 * (yProp0 * src[GetK(xi0, yi0)] + yProp1 * src[GetK(xi0, yi1)]) +
                        xProp1 * (yProp0 * src[GetK(xi1, yi0)] + yProp1 * src[GetK(xi1, yi1)]);
                }
            }

            SetBounds(boundType, dest);
        }
Esempio n. 2
0
        private void StoopidSolve(double[] dest, double[] src, SetBoundsType boundType, double diffuseRate)
        {
            for (int y = 1; y < _ySize - 1; y++)
            {
                int yIndex = y * _xSize;
                for (int x = 1; x < _xSize - 1; x++)
                {
                    int k = x + yIndex;

                    if (_blocked[k])
                    {
                        continue;
                    }

                    dest[k] = (diffuseRate * (src[k - 1] + src[k + 1] + src[k - _xSize] + src[k + _xSize]) + src[k]) / (1 + 4 * diffuseRate);
                }
            }

            SetBounds(boundType, dest);
        }
Esempio n. 3
0
        /// <summary>
        /// Improved gauss-siedel by adding relaxation factor. Overrelaxation at 1.5 seems strong, and higher values
        /// create small-scale instablity (mixing) but seem to produce reasonable incompressiblity even faster.
        /// 4-10 iterations is good for real-time, and not noticably inaccurate. For real accuracy, upwards of 20 is good.
        /// </summary>
        private void LinearSolve(double[] dest, double[] src, SetBoundsType boundType, double diffuseRate, double c)
        {
            double wMax = 1.9;
            double wMin = 1.5;
            for (int i = 0; i < _iterations; i++)
            {
                double w = Math.Max((wMin - wMax) * i / 60.0 + wMax, wMin);
                for (int y = 1; y < _ySize - 1; y++)
                {
                    int yIndex = y * _xSize;
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        int k = x + yIndex;

                        if (_blocked[k])
                        {
                            continue;
                        }

                        dest[k] = dest[k] + w * ((diffuseRate * (dest[k - 1] + dest[k + 1] + dest[k - _xSize] + dest[k + _xSize]) + src[k]) / c - dest[k]);
                    }
                }

                SetBounds(boundType, dest);
            }
        }
Esempio n. 4
0
        private void SetBounds_BlockedCells(SetBoundsType boundType, double[] cells)
        {
            //NOTE: It is safe to ignore blocked cells that are interior (surrounded by other blocked cells)

            IndexLERP[] blocked = null;

            switch (boundType)
            {
                case SetBoundsType.VelocityX:
                    blocked = _blocked_VelocityX;
                    break;

                case SetBoundsType.VelocityY:
                    blocked = _blocked_VelocityY;
                    break;

                case SetBoundsType.Both_Layers:
                case SetBoundsType.Both_Other:
                    blocked = _blocked_Other;
                    break;

                default:
                    throw new ApplicationException("Unknown SetBoundsType: " + boundType.ToString());
            }

            foreach (IndexLERP index in blocked)
            {
                // Add up the neighbors (could be 1 to 8 neighbors)
                double newValue = 0d;

                if (index.Neighbors != null)
                {
                    foreach (var neighbor in index.Neighbors)
                    {
                        newValue += cells[neighbor.Item1] * neighbor.Item2;
                    }
                }

                // Store the average
                cells[index.K] = newValue;
            }
        }
Esempio n. 5
0
 private void Diffuse(double[] dest, double[] src, SetBoundsType boundType, double diff, double dt)
 {
     double a = dt * diff;
     if (_useCheapDiffusion)
     {
         StoopidSolve(dest, src, boundType, a);
     }
     else
     {
         LinearSolve(dest, src, boundType, a, 1 + 4 * a);
     }
 }
Esempio n. 6
0
        private void SetBounds_OpenBox(SetBoundsType boundType, double[] cells)
        {
            switch (boundType)
            {
                case SetBoundsType.VelocityX:
                    #region VelocityX

                    // Set left and right edges to their neighbors
                    //NOTE: Allow outflow, but not full inflow (the inflow becomes self reinforcing, and the whole field becomes a wall of wind)
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = SetBounds_OpenBoxSprtCap(cells[GetK(1, y)], false);
                        cells[GetK(_xSize - 1, y)] = SetBounds_OpenBoxSprtCap(cells[GetK(_xSize - 2, y)], true);
                    }

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, 1)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, _ySize - 2)];
                    }

                    #endregion
                    break;

                case SetBoundsType.VelocityY:
                    #region VelocityY

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        cells[GetK(x, 0)] = SetBounds_OpenBoxSprtCap(cells[GetK(x, 1)], false);
                        cells[GetK(x, _ySize - 1)] = SetBounds_OpenBoxSprtCap(cells[GetK(x, _ySize - 2)], true);
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(1, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(_xSize - 2, y)];
                    }

                    #endregion
                    break;

                case SetBoundsType.Both_Layers:
                case SetBoundsType.Both_Other:
                    #region Both

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, 1)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, _ySize - 2)];
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(1, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(_xSize - 2, y)];
                    }

                    // Set the corners to the average of their two neighbors
                    cells[GetK(0, 0)] = 0.5 * (cells[GetK(0, 1)] + cells[GetK(1, 0)]);
                    cells[GetK(0, _ySize - 1)] = 0.5 * (cells[GetK(1, _ySize - 1)] + cells[GetK(0, _ySize - 2)]);
                    cells[GetK(_xSize - 1, 0)] = 0.5 * (cells[GetK(_xSize - 1, 1)] + cells[GetK(_xSize - 2, 0)]);
                    cells[GetK(_xSize - 1, _ySize - 1)] = 0.5 * (cells[GetK(_xSize - 1, _ySize - 2)] + cells[GetK(_xSize - 2, _ySize - 1)]);

                    #endregion
                    break;

                default:
                    throw new ApplicationException("Unknown SetBoundsType: " + boundType.ToString());
            }
        }
Esempio n. 7
0
        private static void SetBoundry_Closed(SetBoundsType whichSide, double[] cells, int size, BoundrySettings boundrySettings)
        {
            #region X wall

            // When it's the x velocity, it needs to reflect off of this wall.  All other cases slide along it (or in the case of non
            // velocities, just a copy)
            double reflectMult = whichSide == SetBoundsType.VelocityX ? -boundrySettings.WallReflectivity : 1d;

            for (int z = 1; z < size - 1; z++)
            {
                for (int y = 1; y < size - 1; y++)
                {
                    cells[IX(0, y, z, size)] = reflectMult * cells[IX(1, y, z, size)];
                    cells[IX(size - 1, y, z, size)] = reflectMult * cells[IX(size - 2, y, z, size)];
                }
            }

            #endregion
            #region Y wall

            reflectMult = whichSide == SetBoundsType.VelocityY ? -boundrySettings.WallReflectivity : 1d;

            for (int z = 1; z < size - 1; z++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    cells[IX(x, 0, z, size)] = reflectMult * cells[IX(x, 1, z, size)];
                    cells[IX(x, size - 1, z, size)] = reflectMult * cells[IX(x, size - 2, z, size)];
                }
            }

            #endregion
            #region Z wall

            reflectMult = whichSide == SetBoundsType.VelocityZ ? -boundrySettings.WallReflectivity : 1d;

            for (int y = 1; y < size - 1; y++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    cells[IX(x, y, 0, size)] = reflectMult * cells[IX(x, y, 1, size)];
                    cells[IX(x, y, size - 1, size)] = reflectMult * cells[IX(x, y, size - 2, size)];
                }
            }

            #endregion

            #region Edges

            for (int x = 1; x < size - 1; x++)
            {
                cells[IX(x, 0, 0, size)] = 0.5 * (cells[IX(x, 1, 0, size)] + cells[IX(x, 0, 1, size)]);
                cells[IX(x, size - 1, 0, size)] = 0.5 * (cells[IX(x, size - 2, 0, size)] + cells[IX(x, size - 1, 1, size)]);
                cells[IX(x, 0, size - 1, size)] = 0.5 * (cells[IX(x, 1, size - 1, size)] + cells[IX(x, 0, size - 2, size)]);
                cells[IX(x, size - 1, size - 1, size)] = 0.5 * (cells[IX(x, size - 2, size - 1, size)] + cells[IX(x, size - 1, size - 2, size)]);
            }

            for (int y = 1; y < size - 1; y++)
            {
                cells[IX(0, y, 0, size)] = 0.5 * (cells[IX(1, y, 0, size)] + cells[IX(0, y, 1, size)]);
                cells[IX(size - 1, y, 0, size)] = 0.5 * (cells[IX(size - 2, y, 0, size)] + cells[IX(size - 1, y, 1, size)]);
                cells[IX(0, y, size - 1, size)] = 0.5 * (cells[IX(1, y, size - 1, size)] + cells[IX(0, y, size - 2, size)]);
                cells[IX(size - 1, y, size - 1, size)] = 0.5 * (cells[IX(size - 2, y, size - 1, size)] + cells[IX(size - 1, y, size - 2, size)]);
            }

            for (int z = 0; z < size - 1; z++)
            {
                cells[IX(0, 0, z, size)] = 0.5 * (cells[IX(1, 0, z, size)] + cells[IX(0, 1, z, size)]);
                cells[IX(size - 1, 0, z, size)] = 0.5 * (cells[IX(size - 2, 0, z, size)] + cells[IX(size - 1, 1, z, size)]);
                cells[IX(0, size - 1, z, size)] = 0.5 * (cells[IX(1, size - 1, z, size)] + cells[IX(0, size - 2, z, size)]);
                cells[IX(size - 1, size - 1, z, size)] = 0.5 * (cells[IX(size - 2, size - 1, z, size)] + cells[IX(size - 1, size - 2, z, size)]);
            }

            #endregion

            #region Corners

            // Corners take average of neighbors
            cells[IX(0, 0, 0, size)] = ONETHIRD * (
                cells[IX(1, 0, 0, size)] +
                cells[IX(0, 1, 0, size)] +
                cells[IX(0, 0, 1, size)]);

            cells[IX(0, size - 1, 0, size)] = ONETHIRD * (
                cells[IX(1, size - 1, 0, size)] +
                cells[IX(0, size - 2, 0, size)] +
                cells[IX(0, size - 1, 1, size)]);

            cells[IX(0, 0, size - 1, size)] = ONETHIRD * (
                cells[IX(1, 0, size - 1, size)] +
                cells[IX(0, 1, size - 1, size)] +
                cells[IX(0, 0, size - 2, size)]);

            cells[IX(0, size - 1, size - 1, size)] = ONETHIRD * (
                cells[IX(1, size - 1, size - 1, size)] +
                cells[IX(0, size - 2, size - 1, size)] +
                cells[IX(0, size - 1, size - 2, size)]);

            cells[IX(size - 1, 0, 0, size)] = ONETHIRD * (
                cells[IX(size - 2, 0, 0, size)] +
                cells[IX(size - 1, 1, 0, size)] +
                cells[IX(size - 1, 0, 1, size)]);

            cells[IX(size - 1, size - 1, 0, size)] = ONETHIRD * (
                cells[IX(size - 2, size - 1, 0, size)] +
                cells[IX(size - 1, size - 2, 0, size)] +
                cells[IX(size - 1, size - 1, 1, size)]);

            cells[IX(size - 1, 0, size - 1, size)] = ONETHIRD * (
                cells[IX(size - 2, 0, size - 1, size)] +
                cells[IX(size - 1, 1, size - 1, size)] +
                cells[IX(size - 1, 0, size - 2, size)]);

            cells[IX(size - 1, size - 1, size - 1, size)] = ONETHIRD * (
                cells[IX(size - 2, size - 1, size - 1, size)] +
                cells[IX(size - 1, size - 2, size - 1, size)] +
                cells[IX(size - 1, size - 1, size - 2, size)]);

            #endregion
        }
Esempio n. 8
0
        /// <summary>
        /// Allows the fluid to spread out (blurs the fluid)
        /// </summary>
        /// <remarks>
        /// Put a drop of soy sauce in some water, and you'll notice that it doesn't stay still, but it spreads out.  This
        /// happens even if the water and sauce are both perfectly still.  This is called diffusion. We use diffusion both
        /// in the obvious case of making the dye spread out, and also in the less obvious case of making the velocities
        /// of the fluid spread out.
        /// 
        /// Diffuse is really simple; it just precalculates a value and passes everything off to lin_solve.  So that means,
        /// while I know what it does, I don't really know how, since all the work is in that mysterious function
        /// </remarks>
        private static void Diffuse(SetBoundsType whichSide, double[] destination, double[] source, bool[] blocked, double timestep, double diffusion, int iterations, int size, BoundrySettings boundrySettings)
        {
            double a = timestep * diffusion;

            //NOTE: The 2D uses 4.  If 4 is used here, the color just spreads out, so maybe it's 2xDimensions?
            LinearSolve(whichSide, destination, source, blocked, a, 1 + 6 * a, iterations, size, boundrySettings);
        }
Esempio n. 9
0
        /// <remarks>
        /// Every cell has a set of velocities, and these velocities make things move. This is called advection.  As with diffusion, advection
        /// applies both to the dye and to the velocities themselves.
        /// 
        /// This function is responsible for actually moving things around.  To that end, it looks at each cell in turn.  In that cell, it grabs the
        /// velocity, follows that velocity back in time, and sees where it lands.  It then takes a weighted average of the cells around the spot
        /// where it lands, then applies that value to the current cell.
        /// </remarks>
        private static void Advect(SetBoundsType whichSide, double[] dest, double[] source, double[] velocX, double[] velocY, double[] velocZ, bool[] blocked, double timestep, int size, BoundrySettings boundrySettings)
        {
            for (int z = 1; z < size - 1; z++)
            {
                for (int y = 1; y < size - 1; y++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        int index1D = IX(x, y, z, size);

                        if (blocked[index1D])
                        {
                            continue;
                        }

                        // Reverse velocity, since we are interpolating backwards 
                        // xSrc and ySrc is the position of the source density.
                        double xSrc = x - (timestep * velocX[index1D]);
                        double ySrc = y - (timestep * velocY[index1D]);
                        double zSrc = z - (timestep * velocZ[index1D]);

                        if (xSrc < 0.5d) xSrc = 0.5d;
                        if (xSrc > size - 1.5d) xSrc = size - 1.5d;
                        int x0 = (int)xSrc;     // casting to int is also the equivalent of Math.Floor
                        int x1 = x0 + 1;

                        if (ySrc < 0.5d) ySrc = 0.5d;
                        if (ySrc > size - 1.5d) ySrc = size - 1.5d;
                        int y0 = (int)ySrc;
                        int y1 = y0 + 1;

                        if (zSrc < 0.5d) zSrc = 0.5d;
                        if (zSrc > size - 1.5d) zSrc = size - 1.5d;
                        int z0 = (int)zSrc;
                        int z1 = z0 + 1;

                        //Linear interpolation factors. Ex: 0.6 and 0.4
                        double xProp1 = xSrc - x0;
                        double xProp0 = 1d - xProp1;
                        double yProp1 = ySrc - y0;
                        double yProp0 = 1d - yProp1;
                        double zProp1 = zSrc - z0;
                        double zProp0 = 1d - zProp1;

                        // ugly no matter how you nest it
                        dest[index1D] =
                            xProp0 *
                                (yProp0 *
                                    (zProp0 * source[IX(x0, y0, z0, size)] +
                                    zProp1 * source[IX(x0, y0, z1, size)]) +
                                (yProp1 *
                                    (zProp0 * source[IX(x0, y1, z0, size)] +
                                    zProp1 * source[IX(x0, y1, z1, size)]))) +
                            xProp1 *
                                (yProp0 *
                                    (zProp0 * source[IX(x1, y0, z0, size)] +
                                    zProp1 * source[IX(x1, y0, z1, size)]) +
                                (yProp1 *
                                    (zProp0 * source[IX(x1, y1, z0, size)] +
                                    zProp1 * source[IX(x1, y1, z1, size)])));
                    }
                }
            }

            SetBoundry(whichSide, dest, blocked, size, boundrySettings);
        }
Esempio n. 10
0
        private static void SetBoundry_ReachAround(SetBoundsType whichSide, double[] cells, int size, BoundrySettings boundrySettings)
        {
            double average, sum, count;

            bool wrapX = whichSide == SetBoundsType.VelocityX || whichSide == SetBoundsType.Ink;
            bool wrapY = whichSide == SetBoundsType.VelocityY || whichSide == SetBoundsType.Ink;
            bool wrapZ = whichSide == SetBoundsType.VelocityZ || whichSide == SetBoundsType.Ink;

            #region X wall

            if (wrapX)
            {
                // Copy of other side
                for (int z = 1; z < size - 1; z++)
                {
                    for (int y = 1; y < size - 1; y++)
                    {
                        cells[IX(0, y, z, size)] = cells[IX(size - 2, y, z, size)];
                        cells[IX(size - 1, y, z, size)] = cells[IX(1, y, z, size)];
                    }
                }
            }
            else
            {
                // Average
                for (int z = 1; z < size - 1; z++)
                {
                    for (int y = 1; y < size - 1; y++)
                    {
                        average = .5d * (cells[IX(1, y, z, size)] + cells[IX(size - 2, y, z, size)]);

                        cells[IX(0, y, z, size)] = average;
                        cells[IX(size - 1, y, z, size)] = average;
                    }
                }
            }

            #endregion
            #region Y wall

            if (wrapY)
            {
                // Copy of other side
                for (int z = 1; z < size - 1; z++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, 0, z, size)] = cells[IX(x, size - 2, z, size)];
                        cells[IX(x, size - 1, z, size)] = cells[IX(x, 1, z, size)];
                    }
                }
            }
            else
            {
                // Average
                for (int z = 1; z < size - 1; z++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        average = .5d * (cells[IX(x, 1, z, size)] + cells[IX(x, size - 2, z, size)]);

                        cells[IX(x, 0, z, size)] = average;
                        cells[IX(x, size - 1, z, size)] = average;
                    }
                }
            }

            #endregion
            #region Z wall

            if (wrapZ)
            {
                // Copy of other side
                for (int y = 1; y < size - 1; y++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, y, 0, size)] = cells[IX(x, y, size - 2, size)];
                        cells[IX(x, y, size - 1, size)] = cells[IX(x, y, 1, size)];
                    }
                }
            }
            else
            {
                // Average
                for (int y = 1; y < size - 1; y++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        average = .5d * (cells[IX(x, y, 1, size)] + cells[IX(x, y, size - 2, size)]);

                        cells[IX(x, y, 0, size)] = average;
                        cells[IX(x, y, size - 1, size)] = average;
                    }
                }
            }

            #endregion

            #region X edges

            for (int x = 1; x < size - 1; x++)
            {
                // 1
                sum = 0; count = 0;

                sum += cells[IX(x, size - 2, 0, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(x, 1, 0, size)]; count++;
                }

                sum += cells[IX(x, 0, size - 2, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(x, 0, 1, size)]; count++;
                }

                cells[IX(x, 0, 0, size)] = sum / count;

                // 2
                sum = 0; count = 0;

                sum += cells[IX(x, 1, 0, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(x, size - 2, 0, size)]; count++;
                }

                sum += cells[IX(x, size - 1, size - 2, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(x, size - 1, 1, size)]; count++;
                }

                cells[IX(x, size - 1, 0, size)] = sum / count;

                // 3
                sum = 0; count = 0;

                sum += cells[IX(x, size - 2, size - 1, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(x, 1, size - 1, size)]; count++;
                }

                sum += cells[IX(x, 0, 1, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(x, 0, size - 2, size)]; count++;
                }

                cells[IX(x, 0, size - 1, size)] = sum / count;

                // 4
                sum = 0; count = 0;

                sum += cells[IX(x, 1, size - 1, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(x, size - 2, size - 1, size)]; count++;
                }

                sum += cells[IX(x, size - 1, 1, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(x, size - 1, size - 2, size)]; count++;
                }

                cells[IX(x, size - 1, size - 1, size)] = sum / count;
            }

            #endregion
            #region Y edges

            for (int y = 1; y < size - 1; y++)
            {
                // 1
                sum = 0; count = 0;

                sum += cells[IX(size - 2, y, 0, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(1, y, 0, size)]; count++;
                }

                sum += cells[IX(0, y, size - 2, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(0, y, 1, size)]; count++;
                }

                cells[IX(0, y, 0, size)] = sum / count;

                // 2
                sum = 0; count = 0;

                sum += cells[IX(1, y, 0, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(size - 2, y, 0, size)]; count++;
                }

                sum += cells[IX(size - 1, y, size - 2, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(size - 1, y, 1, size)]; count++;
                }

                cells[IX(size - 1, y, 0, size)] = sum / count;

                // 3
                sum = 0; count = 0;

                sum += cells[IX(size - 2, y, size - 1, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(1, y, size - 1, size)]; count++;
                }

                sum += cells[IX(0, y, 1, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(0, y, size - 2, size)]; count++;
                }

                cells[IX(0, y, size - 1, size)] = sum / count;

                // 4
                sum = 0; count = 0;

                sum += cells[IX(1, y, size - 1, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(size - 2, y, size - 1, size)]; count++;
                }

                sum += cells[IX(size - 1, y, 1, size)]; count++;
                if (!wrapZ)
                {
                    sum += cells[IX(size - 1, y, size - 2, size)]; count++;
                }

                cells[IX(size - 1, y, size - 1, size)] = sum / count;
            }

            #endregion
            #region Z edges

            for (int z = 0; z < size - 1; z++)
            {
                // 1
                sum = 0; count = 0;

                sum += cells[IX(size - 2, 0, z, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(1, 0, z, size)]; count++;
                }

                sum += cells[IX(0, size - 2, z, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(0, 1, z, size)]; count++;
                }

                cells[IX(0, 0, z, size)] = sum / count;

                // 2
                sum = 0; count = 0;

                sum += cells[IX(1, 0, z, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(size - 2, 0, z, size)]; count++;
                }

                sum += cells[IX(size - 1, size - 2, z, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(size - 1, 1, z, size)]; count++;
                }

                cells[IX(size - 1, 0, z, size)] = sum / count;

                // 3
                sum = 0; count = 0;

                sum += cells[IX(size - 2, size - 1, z, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(1, size - 1, z, size)]; count++;
                }

                sum += cells[IX(0, 1, z, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(0, size - 2, z, size)]; count++;
                }

                cells[IX(0, size - 1, z, size)] = sum / count;

                // 4
                sum = 0; count = 0;

                sum += cells[IX(1, size - 1, z, size)]; count++;
                if (!wrapX)
                {
                    sum += cells[IX(size - 2, size - 1, z, size)]; count++;
                }

                sum += cells[IX(size - 1, 1, z, size)]; count++;
                if (!wrapY)
                {
                    sum += cells[IX(size - 1, size - 2, z, size)]; count++;
                }

                cells[IX(size - 1, size - 1, z, size)] = sum / count;
            }

            #endregion

            #region Corners

            // 1
            sum = 0; count = 0;

            sum += cells[IX(size - 2, 0, 0, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(1, 0, 0, size)]; count++;
            }

            sum += cells[IX(0, size - 2, 0, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(0, 1, 0, size)]; count++;
            }

            sum += cells[IX(0, 0, size - 2, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(0, 0, 1, size)]; count++;
            }

            cells[IX(0, 0, 0, size)] = sum / count;

            // 2
            sum = 0; count = 0;

            sum += cells[IX(size - 2, size - 1, 0, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(1, size - 1, 0, size)]; count++;
            }

            sum += cells[IX(0, 1, 0, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(0, size - 2, 0, size)]; count++;
            }

            sum += cells[IX(0, size - 1, size - 2, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(0, size - 1, 1, size)]; count++;
            }

            cells[IX(0, size - 1, 0, size)] = sum / count;

            // 3
            sum = 0; count = 0;

            sum += cells[IX(size - 2, 0, size - 1, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(1, 0, size - 1, size)]; count++;
            }

            sum += cells[IX(0, size - 2, size - 1, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(0, 1, size - 1, size)]; count++;
            }

            sum += cells[IX(0, 0, 1, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(0, 0, size - 2, size)]; count++;
            }

            cells[IX(0, 0, size - 1, size)] = sum / count;

            // 4
            sum = 0; count = 0;

            sum += cells[IX(size - 2, size - 1, size - 1, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(1, size - 1, size - 1, size)]; count++;
            }

            sum += cells[IX(0, 1, size - 1, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(0, size - 2, size - 1, size)]; count++;
            }

            sum += cells[IX(0, size - 1, 1, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(0, size - 1, size - 2, size)]; count++;
            }

            cells[IX(0, size - 1, size - 1, size)] = sum / count;

            // 5
            sum = 0; count = 0;

            sum += cells[IX(1, 0, 0, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(size - 2, 0, 0, size)]; count++;
            }

            sum += cells[IX(size - 1, size - 2, 0, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(size - 1, 1, 0, size)]; count++;
            }

            sum += cells[IX(size - 1, 0, size - 2, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(size - 1, 0, 1, size)]; count++;
            }

            cells[IX(size - 1, 0, 0, size)] = sum / count;

            // 6
            sum = 0; count = 0;

            sum += cells[IX(1, size - 1, 0, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(size - 2, size - 1, 0, size)]; count++;
            }

            sum += cells[IX(size - 1, 1, 0, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(size - 1, size - 2, 0, size)]; count++;
            }

            sum += cells[IX(size - 1, size - 1, size - 2, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(size - 1, size - 1, 1, size)]; count++;
            }

            cells[IX(size - 1, size - 1, 0, size)] = sum / count;

            // 7
            sum = 0; count = 0;

            sum += cells[IX(1, 0, size - 1, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(size - 2, 0, size - 1, size)]; count++;
            }

            sum += cells[IX(size - 1, size - 2, size - 1, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(size - 1, 1, size - 1, size)]; count++;
            }

            sum += cells[IX(size - 1, 0, 1, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(size - 1, 0, size - 2, size)]; count++;
            }

            cells[IX(size - 1, 0, size - 1, size)] = sum / count;

            // 8
            sum = 0; count = 0;

            sum += cells[IX(1, size - 1, size - 1, size)]; count++;
            if (!wrapX)
            {
                sum += cells[IX(size - 2, size - 1, size - 1, size)]; count++;
            }

            sum += cells[IX(size - 1, 1, size - 1, size)]; count++;
            if (!wrapY)
            {
                sum += cells[IX(size - 1, size - 2, size - 1, size)]; count++;
            }

            sum += cells[IX(size - 1, size - 1, 1, size)]; count++;
            if (!wrapZ)
            {
                sum += cells[IX(size - 1, size - 1, size - 2, size)]; count++;
            }

            cells[IX(size - 1, size - 1, size - 1, size)] = sum / count;

            #endregion
        }
Esempio n. 11
0
        private static void SetBoundry_BlockedCells(SetBoundsType whichSide, double[] cells, BoundrySettings boundrySettings)
        {
            //NOTE: It is safe to ignore blocked cells that are interior (surrounded by other blocked cells)

            IndexLERP[] blocked = null;

            switch (whichSide)
            {
                case SetBoundsType.VelocityX:
                    blocked = boundrySettings.Blocked_VelocityX;
                    break;

                case SetBoundsType.VelocityY:
                    blocked = boundrySettings.Blocked_VelocityY;
                    break;

                case SetBoundsType.VelocityZ:
                    blocked = boundrySettings.Blocked_VelocityZ;
                    break;

                case SetBoundsType.Ink:
                case SetBoundsType.Other:
                    blocked = boundrySettings.Blocked_Other;
                    break;

                default:
                    throw new ApplicationException("Unknown SetBoundsType: " + whichSide.ToString());
            }

            foreach (IndexLERP index in blocked)
            {
                // Add up the neighbors
                double newValue = 0d;

                if (index.Neighbors != null)
                {
                    foreach (var neighbor in index.Neighbors)
                    {
                        newValue += cells[neighbor.Item1] * neighbor.Item2;
                    }
                }

                // Store the average
                cells[index.Index1D] = newValue;
            }
        }
Esempio n. 12
0
        private static void SetBoundry_OpenSlaved(SetBoundsType whichSide, double[] cells, int size, BoundrySettings boundrySettings)
        {
            double[] source;

            switch (whichSide)
            {
                case SetBoundsType.VelocityX:
                    source = boundrySettings.OpenBorderVelocityX;
                    break;

                case SetBoundsType.VelocityY:
                    source = boundrySettings.OpenBorderVelocityY;
                    break;

                case SetBoundsType.VelocityZ:
                    source = boundrySettings.OpenBorderVelocityZ;
                    break;

                default:
                    // Non velocity can use the standard open method
                    SetBoundry_Open(whichSide, cells, size, boundrySettings);
                    return;
            }

            // When slaved, this field's velocity is just a copy of the source's velocity
            foreach (var index in boundrySettings.OpenBorderCells)
            {
                cells[index.Offset1D] = source[index.Offset1D];
            }
        }
Esempio n. 13
0
        private static void SetBoundry_OpenShared(SetBoundsType whichSide, double[] cells, int size, BoundrySettings boundrySettings)
        {
            // This method is sort of a combination of SetBoundry_Open and SetBoundry_OpenSlaved.  It stores the average of what
            // open would have stored with what slave would have stored: (open + slave) / 2

            double[] source;

            switch (whichSide)
            {
                case SetBoundsType.VelocityX:
                    source = boundrySettings.OpenBorderVelocityX;
                    break;

                case SetBoundsType.VelocityY:
                    source = boundrySettings.OpenBorderVelocityY;
                    break;

                case SetBoundsType.VelocityZ:
                    source = boundrySettings.OpenBorderVelocityZ;
                    break;

                default:
                    // Non velocity can use the standard open method
                    SetBoundry_Open(whichSide, cells, size, boundrySettings);
                    return;
            }

            #region X wall

            int index;

            for (int z = 1; z < size - 1; z++)
            {
                for (int y = 1; y < size - 1; y++)
                {
                    index = IX(0, y, z, size);
                    cells[index] = .5d * (source[index] + cells[IX(1, y, z, size)]);

                    index = IX(size - 1, y, z, size);
                    cells[index] = .5d * (source[index] + cells[IX(size - 2, y, z, size)]);
                }
            }

            #endregion
            #region Y wall

            for (int z = 1; z < size - 1; z++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    index = IX(x, 0, z, size);
                    cells[index] = .5d * (source[index] + cells[IX(x, 1, z, size)]);

                    index = IX(x, size - 1, z, size);
                    cells[index] = .5d * (source[index] + cells[IX(x, size - 2, z, size)]);
                }
            }

            #endregion
            #region Z wall

            for (int y = 1; y < size - 1; y++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    index = IX(x, y, 0, size);
                    cells[index] = .5d * (source[index] + cells[IX(x, y, 1, size)]);

                    index = IX(x, y, size - 1, size);
                    cells[index] = .5d * (source[index] + cells[IX(x, y, size - 2, size)]);
                }
            }

            #endregion

            #region Edges

            double thisValue;

            for (int x = 1; x < size - 1; x++)
            {
                index = IX(x, 0, 0, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, 1, 0, size)], false) : cells[IX(x, 1, 0, size)]) +      // restrict y travel when it's the y veloctiy array
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, 0, 1, size)], false) : cells[IX(x, 0, 1, size)])        // restrict z travel when it's the z velocity array
                    );
                cells[index] = .5d * (source[index] + thisValue);       // now take the average of this field's value with the source.  NOTE: Giving the two equal weight, that's why I don't just add the 3 and divide by 3.

                index = IX(x, size - 1, 0, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, size - 2, 0, size)], true) : cells[IX(x, size - 2, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, size - 1, 1, size)], false) : cells[IX(x, size - 1, 1, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(x, 0, size - 1, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, 1, size - 1, size)], false) : cells[IX(x, 1, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, 0, size - 2, size)], true) : cells[IX(x, 0, size - 2, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(x, size - 1, size - 1, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, size - 2, size - 1, size)], true) : cells[IX(x, size - 2, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, size - 1, size - 2, size)], true) : cells[IX(x, size - 1, size - 2, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);
            }

            for (int y = 1; y < size - 1; y++)
            {
                index = IX(0, y, 0, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, y, 0, size)], false) : cells[IX(1, y, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, y, 1, size)], false) : cells[IX(0, y, 1, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(size - 1, y, 0, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, y, 0, size)], true) : cells[IX(size - 2, y, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, y, 1, size)], false) : cells[IX(size - 1, y, 1, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(0, y, size - 1, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, y, size - 1, size)], false) : cells[IX(1, y, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, y, size - 2, size)], true) : cells[IX(0, y, size - 2, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(size - 1, y, size - 1, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, y, size - 1, size)], true) : cells[IX(size - 2, y, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, y, size - 2, size)], true) : cells[IX(size - 1, y, size - 2, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);
            }

            for (int z = 0; z < size - 1; z++)
            {
                index = IX(0, 0, z, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, z, size)], false) : cells[IX(1, 0, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, z, size)], false) : cells[IX(0, 1, z, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(size - 1, 0, z, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, z, size)], true) : cells[IX(size - 2, 0, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, z, size)], false) : cells[IX(size - 1, 1, z, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(0, size - 1, z, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, z, size)], false) : cells[IX(1, size - 1, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, z, size)], true) : cells[IX(0, size - 2, z, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);

                index = IX(size - 1, size - 1, z, size);
                thisValue = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, z, size)], true) : cells[IX(size - 2, size - 1, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, z, size)], true) : cells[IX(size - 1, size - 2, z, size)])
                    );
                cells[index] = .5d * (source[index] + thisValue);
            }

            #endregion

            #region Corners

            // Corners take average of neighbors

            index = IX(0, 0, 0, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, 0, size)], false) : cells[IX(1, 0, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, 0, size)], false) : cells[IX(0, 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, 0, 1, size)], false) : cells[IX(0, 0, 1, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(0, size - 1, 0, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, 0, size)], false) : cells[IX(1, size - 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, 0, size)], true) : cells[IX(0, size - 2, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, size - 1, 1, size)], false) : cells[IX(0, size - 1, 1, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(0, 0, size - 1, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, size - 1, size)], false) : cells[IX(1, 0, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, size - 1, size)], false) : cells[IX(0, 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, 0, size - 2, size)], true) : cells[IX(0, 0, size - 2, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(0, size - 1, size - 1, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, size - 1, size)], false) : cells[IX(1, size - 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, size - 1, size)], true) : cells[IX(0, size - 2, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, size - 1, size - 2, size)], true) : cells[IX(0, size - 1, size - 2, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(size - 1, 0, 0, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, 0, size)], true) : cells[IX(size - 2, 0, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, 0, size)], false) : cells[IX(size - 1, 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 0, 1, size)], false) : cells[IX(size - 1, 0, 1, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(size - 1, size - 1, 0, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, 0, size)], true) : cells[IX(size - 2, size - 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, 0, size)], true) : cells[IX(size - 1, size - 2, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 1, 1, size)], false) : cells[IX(size - 1, size - 1, 1, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(size - 1, 0, size - 1, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, size - 1, size)], true) : cells[IX(size - 2, 0, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, size - 1, size)], false) : cells[IX(size - 1, 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 0, size - 2, size)], true) : cells[IX(size - 1, 0, size - 2, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            index = IX(size - 1, size - 1, size - 1, size);
            thisValue = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, size - 1, size)], true) : cells[IX(size - 2, size - 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, size - 1, size)], true) : cells[IX(size - 1, size - 2, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 1, size - 2, size)], true) : cells[IX(size - 1, size - 1, size - 2, size)])
                );
            cells[index] = .5d * (source[index] + thisValue);

            #endregion
        }
Esempio n. 14
0
        private static void SetBoundry_Open(SetBoundsType whichSide, double[] cells, int size, BoundrySettings boundrySettings)
        {
            // OpenBox needs to allow open flow for the velocity, but just copy cells for everything else
            //NOTE: Allow outflow, but not full inflow (the inflow becomes self reinforcing, and the whole field becomes a wall of wind)
            //NOTE: Inflow is only an issue along the wall where the corresponding velocity array is parallel (so the velocityX array only needs to worry about the x wall.  The y and z walls are safe to copy values, because the flow is perpendicular to them)

            #region X wall

            if (whichSide == SetBoundsType.VelocityX)
            {
                for (int z = 1; z < size - 1; z++)
                {
                    for (int y = 1; y < size - 1; y++)
                    {
                        cells[IX(0, y, z, size)] = SetBoundry_OpenSprtCap(cells[IX(1, y, z, size)], false);
                        cells[IX(size - 1, y, z, size)] = SetBoundry_OpenSprtCap(cells[IX(size - 2, y, z, size)], true);
                    }
                }
            }
            else
            {
                for (int z = 1; z < size - 1; z++)
                {
                    for (int y = 1; y < size - 1; y++)
                    {
                        cells[IX(0, y, z, size)] = cells[IX(1, y, z, size)];
                        cells[IX(size - 1, y, z, size)] = cells[IX(size - 2, y, z, size)];
                    }
                }
            }

            #endregion
            #region Y wall

            if (whichSide == SetBoundsType.VelocityY)
            {
                for (int z = 1; z < size - 1; z++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, 0, z, size)] = SetBoundry_OpenSprtCap(cells[IX(x, 1, z, size)], false);
                        cells[IX(x, size - 1, z, size)] = SetBoundry_OpenSprtCap(cells[IX(x, size - 2, z, size)], true);
                    }
                }
            }
            else
            {
                for (int z = 1; z < size - 1; z++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, 0, z, size)] = cells[IX(x, 1, z, size)];
                        cells[IX(x, size - 1, z, size)] = cells[IX(x, size - 2, z, size)];
                    }
                }
            }

            #endregion
            #region Z wall

            if (whichSide == SetBoundsType.VelocityZ)
            {
                for (int y = 1; y < size - 1; y++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, y, 0, size)] = SetBoundry_OpenSprtCap(cells[IX(x, y, 1, size)], false);
                        cells[IX(x, y, size - 1, size)] = SetBoundry_OpenSprtCap(cells[IX(x, y, size - 2, size)], true);
                    }
                }
            }
            else
            {
                for (int y = 1; y < size - 1; y++)
                {
                    for (int x = 1; x < size - 1; x++)
                    {
                        cells[IX(x, y, 0, size)] = cells[IX(x, y, 1, size)];
                        cells[IX(x, y, size - 1, size)] = cells[IX(x, y, size - 2, size)];
                    }
                }
            }

            #endregion

            #region Edges

            for (int x = 1; x < size - 1; x++)
            {
                cells[IX(x, 0, 0, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, 1, 0, size)], false) : cells[IX(x, 1, 0, size)]) +      // restrict y travel when it's the y veloctiy array
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, 0, 1, size)], false) : cells[IX(x, 0, 1, size)])        // restrict z travel when it's the z velocity array
                    );

                cells[IX(x, size - 1, 0, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, size - 2, 0, size)], true) : cells[IX(x, size - 2, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, size - 1, 1, size)], false) : cells[IX(x, size - 1, 1, size)])
                    );

                cells[IX(x, 0, size - 1, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, 1, size - 1, size)], false) : cells[IX(x, 1, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, 0, size - 2, size)], true) : cells[IX(x, 0, size - 2, size)])
                    );

                cells[IX(x, size - 1, size - 1, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(x, size - 2, size - 1, size)], true) : cells[IX(x, size - 2, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(x, size - 1, size - 2, size)], true) : cells[IX(x, size - 1, size - 2, size)])
                    );
            }

            for (int y = 1; y < size - 1; y++)
            {
                cells[IX(0, y, 0, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, y, 0, size)], false) : cells[IX(1, y, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, y, 1, size)], false) : cells[IX(0, y, 1, size)])
                    );

                cells[IX(size - 1, y, 0, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, y, 0, size)], true) : cells[IX(size - 2, y, 0, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, y, 1, size)], false) : cells[IX(size - 1, y, 1, size)])
                    );

                cells[IX(0, y, size - 1, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, y, size - 1, size)], false) : cells[IX(1, y, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, y, size - 2, size)], true) : cells[IX(0, y, size - 2, size)])
                    );

                cells[IX(size - 1, y, size - 1, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, y, size - 1, size)], true) : cells[IX(size - 2, y, size - 1, size)]) +
                    (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, y, size - 2, size)], true) : cells[IX(size - 1, y, size - 2, size)])
                    );
            }

            for (int z = 0; z < size - 1; z++)
            {
                cells[IX(0, 0, z, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, z, size)], false) : cells[IX(1, 0, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, z, size)], false) : cells[IX(0, 1, z, size)])
                    );

                cells[IX(size - 1, 0, z, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, z, size)], true) : cells[IX(size - 2, 0, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, z, size)], false) : cells[IX(size - 1, 1, z, size)])
                    );

                cells[IX(0, size - 1, z, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, z, size)], false) : cells[IX(1, size - 1, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, z, size)], true) : cells[IX(0, size - 2, z, size)])
                    );

                cells[IX(size - 1, size - 1, z, size)] = 0.5 * (
                    (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, z, size)], true) : cells[IX(size - 2, size - 1, z, size)]) +
                    (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, z, size)], true) : cells[IX(size - 1, size - 2, z, size)])
                    );
            }

            #region FLAWED

            //double average1, average2, average3, average4;

            //for (int x = 1; x < size - 1; x++)
            //{
            //    average1 = 0.5 * (cells[IX(x, 1, 0, size)] + cells[IX(x, 0, 1, size)]);
            //    average2 = 0.5 * (cells[IX(x, size - 2, size - 1, size)] + cells[IX(x, size - 1, size - 2, size)]);
            //    average3 = 0.5 * (cells[IX(x, size - 2, 0, size)] + cells[IX(x, size - 1, 1, size)]);
            //    average4 = 0.5 * (cells[IX(x, 1, size - 1, size)] + cells[IX(x, 0, size - 2, size)]);

            //    if (whichSide == SetBoundsType.VelocityY || whichSide == SetBoundsType.VelocityZ)
            //    {
            //        average1 = SetBoundry_OpenBoxSprtCap(average1, false);
            //        average2 = SetBoundry_OpenBoxSprtCap(average2, true);
            //        average3 *= OPENINFLOWMULT;
            //        average4 *= OPENINFLOWMULT;
            //    }

            //    cells[IX(x, 0, 0, size)] = average1;
            //    cells[IX(x, size - 1, size - 1, size)] = average2;

            //    cells[IX(x, size - 1, 0, size)] = average3;
            //    cells[IX(x, 0, size - 1, size)] = average4;
            //}

            //for (int y = 1; y < size - 1; y++)
            //{
            //    average1 = 0.5 * (cells[IX(1, y, 0, size)] + cells[IX(0, y, 1, size)]);
            //    average2 = 0.5 * (cells[IX(size - 2, y, size - 1, size)] + cells[IX(size - 1, y, size - 2, size)]);
            //    average3 = 0.5 * (cells[IX(size - 2, y, 0, size)] + cells[IX(size - 1, y, 1, size)]);
            //    average4 = 0.5 * (cells[IX(1, y, size - 1, size)] + cells[IX(0, y, size - 2, size)]);

            //    if (whichSide == SetBoundsType.VelocityX || whichSide == SetBoundsType.VelocityZ)
            //    {
            //        average1 = SetBoundry_OpenBoxSprtCap(average1, false);
            //        average2 = SetBoundry_OpenBoxSprtCap(average2, true);
            //        average3 *= OPENINFLOWMULT;
            //        average4 *= OPENINFLOWMULT;
            //    }

            //    cells[IX(0, y, 0, size)] = average1;
            //    cells[IX(size - 1, y, size - 1, size)] = average2;

            //    cells[IX(size - 1, y, 0, size)] = average3;
            //    cells[IX(0, y, size - 1, size)] = average4;
            //}

            //for (int z = 0; z < size - 1; z++)
            //{
            //    average1 = 0.5 * (cells[IX(1, 0, z, size)] + cells[IX(0, 1, z, size)]);
            //    average2 = 0.5 * (cells[IX(size - 2, size - 1, z, size)] + cells[IX(size - 1, size - 2, z, size)]);
            //    average3 = 0.5 * (cells[IX(size - 2, 0, z, size)] + cells[IX(size - 1, 1, z, size)]);
            //    average4 = 0.5 * (cells[IX(1, size - 1, z, size)] + cells[IX(0, size - 2, z, size)]);

            //    if (whichSide == SetBoundsType.VelocityX || whichSide == SetBoundsType.VelocityY)
            //    {
            //        average1 = SetBoundry_OpenBoxSprtCap(average1, false);
            //        average2 = SetBoundry_OpenBoxSprtCap(average2, true);
            //        average3 *= OPENINFLOWMULT;
            //        average4 *= OPENINFLOWMULT;
            //    }

            //    cells[IX(0, 0, z, size)] = average1;
            //    cells[IX(size - 1, size - 1, z, size)] = average2;

            //    cells[IX(size - 1, 0, z, size)] = average3;
            //    cells[IX(0, size - 1, z, size)] = average4;
            //}

            #endregion

            #endregion

            #region Corners

            // Corners take average of neighbors

            cells[IX(0, 0, 0, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, 0, size)], false) : cells[IX(1, 0, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, 0, size)], false) : cells[IX(0, 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, 0, 1, size)], false) : cells[IX(0, 0, 1, size)])
                );

            cells[IX(0, size - 1, 0, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, 0, size)], false) : cells[IX(1, size - 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, 0, size)], true) : cells[IX(0, size - 2, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, size - 1, 1, size)], false) : cells[IX(0, size - 1, 1, size)])
                );

            cells[IX(0, 0, size - 1, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, 0, size - 1, size)], false) : cells[IX(1, 0, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, 1, size - 1, size)], false) : cells[IX(0, 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, 0, size - 2, size)], true) : cells[IX(0, 0, size - 2, size)])
                );

            cells[IX(0, size - 1, size - 1, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(1, size - 1, size - 1, size)], false) : cells[IX(1, size - 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(0, size - 2, size - 1, size)], true) : cells[IX(0, size - 2, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(0, size - 1, size - 2, size)], true) : cells[IX(0, size - 1, size - 2, size)])
                );

            cells[IX(size - 1, 0, 0, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, 0, size)], true) : cells[IX(size - 2, 0, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, 0, size)], false) : cells[IX(size - 1, 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 0, 1, size)], false) : cells[IX(size - 1, 0, 1, size)])
                );

            cells[IX(size - 1, size - 1, 0, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, 0, size)], true) : cells[IX(size - 2, size - 1, 0, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, 0, size)], true) : cells[IX(size - 1, size - 2, 0, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 1, 1, size)], false) : cells[IX(size - 1, size - 1, 1, size)])
                );

            cells[IX(size - 1, 0, size - 1, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, 0, size - 1, size)], true) : cells[IX(size - 2, 0, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 1, size - 1, size)], false) : cells[IX(size - 1, 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, 0, size - 2, size)], true) : cells[IX(size - 1, 0, size - 2, size)])
                );

            cells[IX(size - 1, size - 1, size - 1, size)] = ONETHIRD * (
                (whichSide == SetBoundsType.VelocityX ? SetBoundry_OpenSprtCap(cells[IX(size - 2, size - 1, size - 1, size)], true) : cells[IX(size - 2, size - 1, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityY ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 2, size - 1, size)], true) : cells[IX(size - 1, size - 2, size - 1, size)]) +
                (whichSide == SetBoundsType.VelocityZ ? SetBoundry_OpenSprtCap(cells[IX(size - 1, size - 1, size - 2, size)], true) : cells[IX(size - 1, size - 1, size - 2, size)])
                );


            #region FLAWED

            //double average;
            //bool isVelocity = whichSide == SetBoundsType.VelocityX || whichSide == SetBoundsType.VelocityY || whichSide == SetBoundsType.VelocityZ;

            //// 1
            //average = ONETHIRD * (
            //    cells[IX(1, 0, 0, size)] +
            //    cells[IX(0, 1, 0, size)] +
            //    cells[IX(0, 0, 1, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(0, 0, 0, size)] = average;

            //// 2
            //average = ONETHIRD * (
            //    cells[IX(1, size - 1, 0, size)] +
            //    cells[IX(0, size - 2, 0, size)] +
            //    cells[IX(0, size - 1, 1, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(0, size - 1, 0, size)] = average;

            //// 3
            //average = ONETHIRD * (
            //    cells[IX(1, 0, size - 1, size)] +
            //    cells[IX(0, 1, size - 1, size)] +
            //    cells[IX(0, 0, size - 2, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(0, 0, size - 1, size)] = average;

            //// 4
            //average = ONETHIRD * (
            //    cells[IX(1, size - 1, size - 1, size)] +
            //    cells[IX(0, size - 2, size - 1, size)] +
            //    cells[IX(0, size - 1, size - 2, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(0, size - 1, size - 1, size)] = average;

            //// 5
            //average = ONETHIRD * (
            //    cells[IX(size - 2, 0, 0, size)] +
            //    cells[IX(size - 1, 1, 0, size)] +
            //    cells[IX(size - 1, 0, 1, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(size - 1, 0, 0, size)] = average;

            //// 6
            //average = ONETHIRD * (
            //    cells[IX(size - 2, size - 1, 0, size)] +
            //    cells[IX(size - 1, size - 2, 0, size)] +
            //    cells[IX(size - 1, size - 1, 1, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(size - 1, size - 1, 0, size)] = average;

            //// 7
            //average = ONETHIRD * (
            //    cells[IX(size - 2, 0, size - 1, size)] +
            //    cells[IX(size - 1, 1, size - 1, size)] +
            //    cells[IX(size - 1, 0, size - 2, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(size - 1, 0, size - 1, size)] = average;

            //// 8
            //average = ONETHIRD * (
            //    cells[IX(size - 2, size - 1, size - 1, size)] +
            //    cells[IX(size - 1, size - 2, size - 1, size)] +
            //    cells[IX(size - 1, size - 1, size - 2, size)]);

            //if (isVelocity) average *= OPENINFLOWMULT;

            //cells[IX(size - 1, size - 1, size - 1, size)] = average;

            #endregion

            #endregion
        }
Esempio n. 15
0
        private void SetBounds(SetBoundsType boundType, double[] cells)
        {
            // Outer Edges
            switch (_boundryType)
            {
                case FluidFieldBoundryType2D.Closed:
                    SetBounds_ClosedBox(boundType, cells);
                    break;

                case FluidFieldBoundryType2D.Open:
                    SetBounds_OpenBox(boundType, cells);
                    break;

                case FluidFieldBoundryType2D.WrapAround:
                    SetBounds_WrapAroundBox(boundType, cells);
                    break;

                default:
                    throw new ApplicationException("Unknown FluidFieldBoundryType2D: " + _boundryType.ToString());
            }

            // Blocked Cells
            if (_hasBlockedCells)
            {
                // This has similar logic to closed box, but applied facing outward around the blocked cells
                //SetBounds_BlockedCells(boundType, cells);
                SetBounds_BlockedCells(boundType, cells);
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Not exactly sure how this method works, it's solving a linear differential equation of some sort
        /// </summary>
        /// <remarks>
        ///  This runs through the whole array and sets each cell to a combination of its neighbors.  It does this several times; the more
        ///  iterations it does, the more accurate the results, but the slower things run.  (4 iterations is a good number to use).
        ///  
        /// After each iteration, it resets the boundaries so the calculations don't explode.
        /// </remarks>
        private static void LinearSolve(SetBoundsType whichSide, double[] dest, double[] source, bool[] blocked, double a, double c, int iterations, int size, BoundrySettings boundrySettings)
        {
            double cRecip = 1d / c;

            int index;

            for (int cntr = 0; cntr < iterations; cntr++)
            {
                for (int z = 1; z < size - 1; z++)
                {
                    for (int y = 1; y < size - 1; y++)
                    {
                        for (int x = 1; x < size - 1; x++)
                        {
                            index = IX(x, y, z, size);

                            if (blocked[index])
                            {
                                continue;
                            }

                            dest[index] =
                                    (source[IX(x, y, z, size)]
                                        + a * (dest[IX(x + 1, y, z, size)]
                                                + dest[IX(x - 1, y, z, size)]
                                                + dest[IX(x, y + 1, z, size)]
                                                + dest[IX(x, y - 1, z, size)]
                                                + dest[IX(x, y, z + 1, size)]
                                                + dest[IX(x, y, z - 1, size)]
                                       )) * cRecip;
                        }
                    }
                }

                SetBoundry(whichSide, dest, blocked, size, boundrySettings);
            }
        }
Esempio n. 17
0
        private void SetBounds_ClosedBox(SetBoundsType boundType, double[] cells)
        {
            switch (boundType)
            {
                case SetBoundsType.VelocityX:
                    #region VelocityX

                    // For x velocity, reflect off the y walls, and slide along the x walls

                    // Reflect the left and right edges
                    for (int y = 0; y < _ySize; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(1, y)] * -_wallReflectivity;
                        cells[GetK(_xSize - 1, y)] = cells[GetK(_xSize - 2, y)] * -_wallReflectivity;
                    }

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)        //NOTE: the above loop is 0 to size, but this is 1 to size-1 so that the corners don't get double set
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, 1)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, _ySize - 2)];
                    }

                    #endregion
                    break;

                case SetBoundsType.VelocityY:
                    #region VelocityY

                    // For y velocity, reflect off the x walls, and slide along the y walls

                    // Reflect the top and bottom edges
                    for (int x = 0; x < _xSize; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, 1)] * -_wallReflectivity;
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, _ySize - 2)] * -_wallReflectivity;
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(1, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(_xSize - 2, y)];
                    }

                    #endregion
                    break;

                case SetBoundsType.Both_Layers:
                case SetBoundsType.Both_Other:
                    #region Both

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, 1)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, _ySize - 2)];
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(1, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(_xSize - 2, y)];
                    }

                    // Set the corners to the average of their two neighbors
                    cells[GetK(0, 0)] = 0.5 * (cells[GetK(0, 1)] + cells[GetK(1, 0)]);
                    cells[GetK(0, _ySize - 1)] = 0.5 * (cells[GetK(1, _ySize - 1)] + cells[GetK(0, _ySize - 2)]);
                    cells[GetK(_xSize - 1, 0)] = 0.5 * (cells[GetK(_xSize - 1, 1)] + cells[GetK(_xSize - 2, 0)]);
                    cells[GetK(_xSize - 1, _ySize - 1)] = 0.5 * (cells[GetK(_xSize - 1, _ySize - 2)] + cells[GetK(_xSize - 2, _ySize - 1)]);

                    #endregion
                    break;

                default:
                    throw new ApplicationException("Unknown SetBoundsType: " + boundType.ToString());
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Sets the boundary cells at the outer edges of the cube so they perfectly counteract their neighbor
        /// </summary>
        /// <remarks>
        /// This is a way to keep fluid from leaking out of the box.  (not having walls really screws up the simulation code).
        /// Walls are added by treating the outer layer of cells as the wall.  Basically, every velocity in the layer next to this
        /// outer layer is mirrored.  So when you have some velocity towards the wall in the next-to-outer layer, the wall
        /// gets a velocity that perfectly counters it.
        /// 
        /// 
        /// Say we're at the left edge of the cube. The left cell is the boundary cell that needs to counteract its neighbor, the
        /// right cell. The right cell has a velocity that's up and to the left.
        /// 
        /// The boundary cell's x velocity needs to be opposite its neighbor, but its y velocity needs to be equal to its neighbor.
        /// This will produce a result that counteracts the motion of the fluid which would take it through the wall, and preserves
        /// the rest of the motion.
        /// 
        /// So what action is taken depends on which array is passed in; if we're dealing with x velocities, then we have to set
        /// the boundary cell's value to the opposite of its neighbor, but for everything else we set it to be the same.
        ///
        /// 
        /// This function also sets corners. This is done very simply, by setting each corner cell equal to the average of its three
        /// neighbors.
        /// </remarks>
        private static void SetBoundry_ORIG(SetBoundsType whichSide, double[] array, int size, BoundrySettings boundrySettings)
        {
            const double ONETHIRD = 1d / 3d;

            // Reflect the walls
            //NOTE: These arrays go from 1 to length-1.  The corners are handled later

            // X wall
            for (int z = 1; z < size - 1; z++)
            {
                for (int y = 1; y < size - 1; y++)
                {
                    array[IX(0, y, z, size)] = whichSide == SetBoundsType.VelocityX ? -array[IX(1, y, z, size)] : array[IX(1, y, z, size)];
                    array[IX(size - 1, y, z, size)] = whichSide == SetBoundsType.VelocityX ? -array[IX(size - 2, y, z, size)] : array[IX(size - 2, y, z, size)];
                }
            }

            // Y wall
            for (int z = 1; z < size - 1; z++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    array[IX(x, 0, z, size)] = whichSide == SetBoundsType.VelocityY ? -array[IX(x, 1, z, size)] : array[IX(x, 1, z, size)];
                    array[IX(x, size - 1, z, size)] = whichSide == SetBoundsType.VelocityY ? -array[IX(x, size - 2, z, size)] : array[IX(x, size - 2, z, size)];
                }
            }

            // Z wall
            for (int y = 1; y < size - 1; y++)
            {
                for (int x = 1; x < size - 1; x++)
                {
                    array[IX(x, y, 0, size)] = whichSide == SetBoundsType.VelocityZ ? -array[IX(x, y, 1, size)] : array[IX(x, y, 1, size)];
                    array[IX(x, y, size - 1, size)] = whichSide == SetBoundsType.VelocityZ ? -array[IX(x, y, size - 2, size)] : array[IX(x, y, size - 2, size)];
                }
            }


            // Corners take average of neighbors
            array[IX(0, 0, 0, size)] = ONETHIRD *
                                            (array[IX(1, 0, 0, size)]
                                          + array[IX(0, 1, 0, size)]
                                          + array[IX(0, 0, 1, size)]);

            array[IX(0, size - 1, 0, size)] = ONETHIRD *
                                            (array[IX(1, size - 1, 0, size)]
                                          + array[IX(0, size - 2, 0, size)]
                                          + array[IX(0, size - 1, 1, size)]);

            array[IX(0, 0, size - 1, size)] = ONETHIRD *
                                            (array[IX(1, 0, size - 1, size)]
                                          + array[IX(0, 1, size - 1, size)]
                                          + array[IX(0, 0, size - 2, size)]);

            array[IX(0, size - 1, size - 1, size)] = ONETHIRD *
                                            (array[IX(1, size - 1, size - 1, size)]
                                          + array[IX(0, size - 2, size - 1, size)]
                                          + array[IX(0, size - 1, size - 2, size)]);

            array[IX(size - 1, 0, 0, size)] = ONETHIRD *
                                            (array[IX(size - 2, 0, 0, size)]
                                          + array[IX(size - 1, 1, 0, size)]
                                          + array[IX(size - 1, 0, 1, size)]);

            array[IX(size - 1, size - 1, 0, size)] = ONETHIRD *
                                            (array[IX(size - 2, size - 1, 0, size)]
                                          + array[IX(size - 1, size - 2, 0, size)]
                                          + array[IX(size - 1, size - 1, 1, size)]);

            array[IX(size - 1, 0, size - 1, size)] = ONETHIRD *
                                            (array[IX(size - 2, 0, size - 1, size)]
                                          + array[IX(size - 1, 1, size - 1, size)]
                                          + array[IX(size - 1, 0, size - 2, size)]);

            array[IX(size - 1, size - 1, size - 1, size)] = ONETHIRD *
                                            (array[IX(size - 2, size - 1, size - 1, size)]
                                          + array[IX(size - 1, size - 2, size - 1, size)]
                                          + array[IX(size - 1, size - 1, size - 2, size)]);
        }
Esempio n. 19
0
        private void SetBounds_WrapAroundBox(SetBoundsType boundType, double[] cells)
        {
            switch (boundType)
            {
                case SetBoundsType.VelocityX:
                    #region VelocityX

                    // Set left and right edges to the opposite edge neighbors
                    for (int y = 0; y < _ySize; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(_xSize - 2, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(1, y)];
                    }

                    // Set top and bottom edges to the average of their above/below neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        double average = .5d * (cells[GetK(x, 1)] + cells[GetK(x, _ySize - 2)]);

                        cells[GetK(x, 0)] = average;
                        cells[GetK(x, _ySize - 1)] = average;
                    }

                    #endregion
                    break;

                case SetBoundsType.VelocityY:
                    #region VelocityY

                    // Set top and bottom edges to the opposite edge neighbors
                    for (int x = 0; x < _xSize; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, _ySize - 2)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, 1)];
                    }

                    // Set left and right edges to the average of their left/right neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        double average = .5d * (cells[GetK(1, y)] + cells[GetK(_xSize - 2, y)]);

                        cells[GetK(0, y)] = average;
                        cells[GetK(_xSize - 1, y)] = average;
                    }

                    #endregion
                    break;

                case SetBoundsType.Both_Layers:
                    #region Both_Layers (wrap layers)

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        cells[GetK(x, 0)] = cells[GetK(x, _ySize - 2)];
                        cells[GetK(x, _ySize - 1)] = cells[GetK(x, 1)];
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        cells[GetK(0, y)] = cells[GetK(_xSize - 2, y)];
                        cells[GetK(_xSize - 1, y)] = cells[GetK(1, y)];
                    }

                    //TODO: Wrap this around as well (or just consider more cells when averaging)
                    // Set the corners to the average of their two neighbors
                    cells[GetK(0, 0)] = 0.5 * (cells[GetK(0, 1)] + cells[GetK(1, 0)]);
                    cells[GetK(0, _ySize - 1)] = 0.5 * (cells[GetK(1, _ySize - 1)] + cells[GetK(0, _ySize - 2)]);
                    cells[GetK(_xSize - 1, 0)] = 0.5 * (cells[GetK(_xSize - 1, 1)] + cells[GetK(_xSize - 2, 0)]);
                    cells[GetK(_xSize - 1, _ySize - 1)] = 0.5 * (cells[GetK(_xSize - 1, _ySize - 2)] + cells[GetK(_xSize - 2, _ySize - 1)]);

                    #endregion
                    break;

                case SetBoundsType.Both_Other:
                    #region Both_Other (standard)

                    // Set top and bottom edges to their neighbors
                    for (int x = 1; x < _xSize - 1; x++)
                    {
                        double average = .5d * (cells[GetK(x, 1)] + cells[GetK(x, _ySize - 2)]);

                        cells[GetK(x, 0)] = average;
                        cells[GetK(x, _ySize - 1)] = average;
                    }

                    // Set left and right edges to their neighbors
                    for (int y = 1; y < _ySize - 1; y++)
                    {
                        double average = .5d * (cells[GetK(1, y)] + cells[GetK(_xSize - 2, y)]);

                        cells[GetK(0, y)] = average;
                        cells[GetK(_xSize - 1, y)] = average;
                    }

                    // Set the corners to the average of their two neighbors
                    cells[GetK(0, 0)] = 0.5 * (cells[GetK(0, 1)] + cells[GetK(1, 0)]);
                    cells[GetK(0, _ySize - 1)] = 0.5 * (cells[GetK(1, _ySize - 1)] + cells[GetK(0, _ySize - 2)]);
                    cells[GetK(_xSize - 1, 0)] = 0.5 * (cells[GetK(_xSize - 1, 1)] + cells[GetK(_xSize - 2, 0)]);
                    cells[GetK(_xSize - 1, _ySize - 1)] = 0.5 * (cells[GetK(_xSize - 1, _ySize - 2)] + cells[GetK(_xSize - 2, _ySize - 1)]);

                    #endregion
                    break;

                default:
                    throw new ApplicationException("Unknown SetBoundsType: " + boundType.ToString());
            }
        }
Esempio n. 20
0
        private static void SetBoundry(SetBoundsType whichSide, double[] cells, bool[] blocked, int size, BoundrySettings boundrySettings)
        {
            // Outer Edges
            switch (boundrySettings.BoundryType)
            {
                case FluidFieldBoundryType3D.Closed:
                    SetBoundry_Closed(whichSide, cells, size, boundrySettings);
                    break;

                case FluidFieldBoundryType3D.Open:
                    SetBoundry_Open(whichSide, cells, size, boundrySettings);
                    break;

                case FluidFieldBoundryType3D.Open_Shared:
                    SetBoundry_OpenShared(whichSide, cells, size, boundrySettings);
                    break;

                case FluidFieldBoundryType3D.Open_Slaved:
                    SetBoundry_OpenSlaved(whichSide, cells, size, boundrySettings);
                    break;

                case FluidFieldBoundryType3D.WrapAround:
                    SetBoundry_ReachAround(whichSide, cells, size, boundrySettings);
                    break;

                default:
                    throw new ApplicationException("Unknown FluidFieldBoundryType3D: " + boundrySettings.BoundryType.ToString());
            }

            // Blocked Cells
            if (boundrySettings.HasBlockedCells)
            {
                // This has similar logic to closed box, but applied facing outward around the blocked cells
                SetBoundry_BlockedCells(whichSide, cells, boundrySettings);
            }
        }