Example #1
0
    void AggregateClusters(uint uParentLayer)
    {
        // number of cells in each grid cluster
        uint[] pClusterDims = mInfluenceTree.GetDecimations((int)uParentLayer);

        uint[] numCells = { mInfluenceTree[uParentLayer].GetNumCells(0), mInfluenceTree[uParentLayer].GetNumCells(1), mInfluenceTree[uParentLayer].GetNumCells(2) };
        uint   numXY    = mInfluenceTree[uParentLayer].GetNumPoints(0) * mInfluenceTree[uParentLayer].GetNumPoints(1);

        // (Since this loop writes to each parent cell, it should readily parallelize without contention.)
        uint[] idxParent = new uint[3];
        for (idxParent[2] = 0; idxParent[2] < numCells[2]; ++idxParent[2])
        {
            uint offsetZ = idxParent[2] * numXY;
            for (idxParent[1] = 0; idxParent[1] < numCells[1]; ++idxParent[1])
            {
                uint offsetYZ = idxParent[1] * mInfluenceTree[uParentLayer].GetNumPoints(0) + offsetZ;
                for (idxParent[0] = 0; idxParent[0] < numCells[0]; ++idxParent[0])
                {   // For each cell in the parent layer...
                    uint offsetXYZ = idxParent[0] + offsetYZ;

                    UniformGrid <Vorton> rChildLayer = mInfluenceTree[uParentLayer - 1];
                    VortonClusterAux     vortAux     = new VortonClusterAux();
                    uint[] clusterMinIndices         = mInfluenceTree.GetChildClusterMinCornerIndex(pClusterDims, idxParent);;

                    uint[] increment  = { 0, 0, 0 };
                    uint   numXchild  = rChildLayer.GetNumPoints(0);
                    uint   numXYchild = numXchild * rChildLayer.GetNumPoints(1);
                    // For each cell of child layer in this grid cluster...
                    for (increment[2] = 0; increment[2] < pClusterDims[2]; ++increment[2])
                    {
                        uint childOffsetZ = (clusterMinIndices[2] + increment[2]) * numXYchild;
                        for (increment[1] = 0; increment[1] < pClusterDims[1]; ++increment[1])
                        {
                            uint childOffsetYZ = (clusterMinIndices[1] + increment[1]) * numXchild + childOffsetZ;
                            for (increment[0] = 0; increment[0] < pClusterDims[0]; ++increment[0])
                            {
                                uint   childOffsetXYZ = (clusterMinIndices[0] + increment[0]) + childOffsetYZ;
                                Vorton rVortonChild   = rChildLayer[childOffsetXYZ];
                                float  vortMag        = rVortonChild.vorticity.magnitude;

                                // Aggregate vorton cluster from child layer into parent layer:
                                mInfluenceTree[uParentLayer][offsetXYZ].position  += rVortonChild.position * vortMag;
                                mInfluenceTree[uParentLayer][offsetXYZ].vorticity += rVortonChild.vorticity;
                                vortAux.mVortNormSum += vortMag;
                                if (rVortonChild.radius != 0.0f)
                                {
                                    mInfluenceTree[uParentLayer][offsetXYZ].radius = rVortonChild.radius;
                                }
                            }
                        }
                    }
                    // Normalize weighted position sum to obtain center-of-vorticity.
                    // (See analogous code in MakeBaseVortonGrid.)
                    mInfluenceTree[uParentLayer][offsetXYZ].position /= vortAux.mVortNormSum;
                }
            }
        }
    }
Example #2
0
    /*
     *  Advect vortons using velocity field
     *
     *  timeStep - amount of time by which to advance simulation
     *
     */
    void AdvectVortons(float timeStep)
    {
        int numVortons = mVortons.Count;

        for (int offset = 0; offset < numVortons; ++offset)
        {   // For each vorton...
            Vorton rVorton = mVortons[offset];

            Vector3 velocity = ((Vector)mVelGrid.Interpolate(rVorton.position)).v;
            mVortons[offset].position += velocity * timeStep;
            mVortons[offset].velocity  = velocity;  // Cache this for use in collisions with rigid bodies.
        }
    }
Example #3
0
    /*
     *  Computes the total circulation and linear impulse of all vortons in this simulation.
     *
     *  vCirculation - Total circulation, the volume integral of the vorticity.
     *  vLinearImpulse - Volume integral of circulation weighted by position.
     */
    void ConservedQuantities()
    {
        // Zero accumulators.
        mCirculationInitial = mLinearImpulseInitial = new Vector3(0.0f, 0.0f, 0.0f);
        int numVortons = mVortons.Count;

        for (int iVorton = 0; iVorton < numVortons; ++iVorton)
        {   // For each vorton in this simulation...
            Vorton Vorton        = mVortons[iVorton];
            float  volumeElement = (mVortons[iVorton].radius * mVortons[iVorton].radius * mVortons[iVorton].radius) * 8.0f;
            // Accumulate total circulation.
            mCirculationInitial += mVortons[iVorton].vorticity * volumeElement;
            // Accumulate total linear impulse.
            mLinearImpulseInitial += Vector3.Cross(mVortons[iVorton].position, mVortons[iVorton].vorticity * volumeElement);
        }
    }
    void AssignVorticity(float fMagnitude, uint numVortonsMax, IVorticityDistribution vorticityDistribution)
    {
        Vector3             vDimensions = vorticityDistribution.GetDomainSize(); // length of each side of grid box
        Vector3             vCenter     = (vorticityDistribution).GetCenter();   // Center of vorticity distribution
        Vector3             vMin        = (vCenter - 0.5f * vDimensions);        // Minimum corner of box containing vortons
        Vector3             vMax        = (vMin + vDimensions);                  // Maximum corner of box containing vortons
        UniformGridGeometry skeleton    = new UniformGridGeometry(numVortonsMax, vMin, vMax, true);

        // number of grid cells in each direction of virtual uniform grid
        int[] numCells = { (int)Mathf.Max(1, skeleton.GetNumCells(0))
                           ,                 (int)Mathf.Max(1, skeleton.GetNumCells(1))
                           ,                 (int)Mathf.Max(1, skeleton.GetNumCells(2)) };

        // Total number of cells should be as close to numVortonsMax as possible without going over.
        // Worst case allowable difference would be numVortonsMax=7 and numCells in each direction is 1 which yields a ratio of 1/7.
        // But in typical situations, the user would like expect total number of virtual cells to be closer to numVortonsMax than that.
        // E.g. if numVortonsMax=8^3=512 somehow yielded numCells[0]=numCells[1]=numCells[2]=7 then the ratio would be 343/512~=0.67.
        while (numCells[0] * numCells[1] * numCells[2] > numVortonsMax)
        {   // Number of cells is excessive.
            // This can happen when the trial number of cells in any direction is less than 1 -- then the other two will likely be too large.
            numCells[0] = (int)Mathf.Max(1, numCells[0] / 2);
            numCells[1] = (int)Mathf.Max(1, numCells[1] / 2);
            numCells[2] = (int)Mathf.Max(1, numCells[2] / 2);
        }

        float[] oneOverN     = { 1.0f / (float)(numCells[0]), 1.0f / (float)(numCells[1]), 1.0f / (float)(numCells[2]) };
        Vector3 gridCellSize = new Vector3(vDimensions.x * oneOverN[0], vDimensions.y * oneOverN[1], vDimensions.z * oneOverN[2]);
        float   vortonRadius = Mathf.Pow(gridCellSize.x * gridCellSize.y * gridCellSize.z, 1.0f / 3.0f) * 0.5f;

        if (0.0f == vDimensions.z)
        {   // z size is zero, so domain is 2D.
            vortonRadius = Mathf.Pow(gridCellSize.x * gridCellSize.y, 0.5f) * 0.5f;
        }
        Vector3 vNoise = (0.0f * gridCellSize);

        //-----------------------------------------------------------------------
        // Iterate through each point in a uniform grid.
        // If probe position is inside vortex core, add a vorton there.
        // This loop could be rewritten such that it only visits points inside the core,
        // but this loop structure can readily be reused for a wide variety of configurations.
        Vector3 position = new Vector3(0.0f, 0.0f, 0.0f); // vorton position

        int[] index = new int[3];                         // index of each position visited

        for (index[2] = 0; index[2] < numCells[2]; ++index[2])
        {   // For each z-coordinate...
            position.z = ((float)(index[2]) + 0.25f) * gridCellSize.z + vMin.z;
            for (index[1] = 0; index[1] < numCells[1]; ++index[1])
            {   // For each y-coordinate...
                position.y = ((float)(index[1]) + 0.25f) * gridCellSize.y + vMin.y;
                for (index[0] = 0; index[0] < numCells[0]; ++index[0])
                {   // For each x-coordinate...
                    position.x = ((float)(index[0]) + 0.25f) * gridCellSize.x + vMin.x;
                    position  += Random.Range(-1, 1) * (vNoise);
                    Vector3 vorticity = Vector3.zero;
                    vorticityDistribution.AssignVorticity(ref vorticity, position, vCenter);
                    Vorton vorton = new Vorton(position, vorticity * fMagnitude, vortonRadius);
                    if (vorticity.sqrMagnitude > global.GlobalVar.sTiny)
                    {   // Vorticity is significantly non-zero.
                        mVortonSim.AddVorton(vorton);
                    }
                }
            }
        }
        //-----------------------------------------------------------------------
    }
Example #5
0
    /*
     *  Diffuse vorticity using a particle strength exchange method.
     *
     *  This routine partitions space into cells using the same grid
     *  as the "base vorton" grid.  Each vorton gets assigned to the
     *  cell that contains it.  Then, each vorton exchanges some
     *  of its vorticity with its neighbors in adjacent cells.
     *
     *  This routine makes some simplifying assumptions to speed execution:
     *
     *      -   Distance does not influence the amount of vorticity exchanged,
     *          except in as much as only vortons within a certain region of
     *          each other exchange vorticity.  This amounts to saying our kernel,
     *          eta, is a top-hat function.
     *
     *      -   Theoretically, if an adjacent cell contains no vortons
     *          then this simulation should generate vorticity within
     *          that cell, e.g. by creating a new vorton in the adjacent cell.
     *
     *      -   This simulation reduces the vorticity of each vorton, alleging
     *          that this vorticity is dissipated analogously to how energy
     *          dissipates at Kolmogorov microscales.  This treatment is not
     *          realistic but it retains qualitative characteristics that we
     *          want, e.g. that the flow dissipates at a rate related to viscosity.
     *          Dissipation in real flows is a more complicated phenomenon.
     *
     *  see Degond & Mas-Gallic (1989): The weighted particle method for
     *      convection-diffusion equations, part 1: the case of an isotropic viscosity.
     *      Math. Comput., v. 53, n. 188, pp. 485-507, October.
     *
     *  timeStep - amount of time by which to advance simulation
     *
     *  This routine assumes CreateInfluenceTree has already executed.
     *
     */
    void DiffuseVorticityPSE(float timeStep)
    {
        // Phase 1: Partition vortons

        // Create a spatial partition for the vortons.
        // Each cell contains a dynamic array of integers
        // whose values are offsets into mVortons.
        UniformGrid <IntList> ugVortRef = new UniformGrid <IntList>(mInfluenceTree[0]);

        ugVortRef.Init();

        int numVortons = mVortons.Count;

        for (int offset = 0 /* Start at 0th vorton */; offset < numVortons; ++offset)
        {   // For each vorton...
            // Insert the vorton's offset into the spatial partition.
            ugVortRef[mVortons[offset].position].list.Add(offset);
        }

        // Phase 2: Exchange vorticity with nearest neighbors

        uint nx   = ugVortRef.GetNumPoints(0);
        uint nxm1 = nx - 1;
        uint ny   = ugVortRef.GetNumPoints(1);
        uint nym1 = ny - 1;
        uint nxy  = nx * ny;
        uint nz   = ugVortRef.GetNumPoints(2);
        uint nzm1 = nz - 1;

        uint[] idx = new uint[3];
        for (idx[2] = 0; idx[2] < nzm1; ++idx[2])
        {   // For all points along z except the last...
            uint offsetZ0 = idx[2] * nxy;
            uint offsetZp = (idx[2] + 1) * nxy;

            for (idx[1] = 0; idx[1] < nym1; ++idx[1])
            {   // For all points along y except the last...
                uint offsetY0Z0 = idx[1] * nx + offsetZ0;
                uint offsetYpZ0 = (idx[1] + 1) * nx + offsetZ0;
                uint offsetY0Zp = idx[1] * nx + offsetZp;

                for (idx[0] = 0; idx[0] < nxm1; ++idx[0])
                {   // For all points along x except the last...
                    uint offsetX0Y0Z0 = idx[0] + offsetY0Z0;

                    for (int ivHere = 0; ivHere < ugVortRef[offsetX0Y0Z0].list.Count; ++ivHere)
                    {   // For each vorton in this gridcell...
                        int     rVortIdxHere   = ugVortRef[offsetX0Y0Z0].list[ivHere];
                        Vorton  rVortonHere    = mVortons[rVortIdxHere];
                        Vector3 rVorticityHere = rVortonHere.vorticity;

                        // Diffuse vorticity with other vortons in this same cell:
                        for (int ivThere = ivHere + 1; ivThere < ugVortRef[offsetX0Y0Z0].list.Count; ++ivThere)
                        {   // For each OTHER vorton within this same cell...
                            int     rVortIdxThere   = ugVortRef[offsetX0Y0Z0].list[ivThere];
                            Vorton  rVortonThere    = mVortons[rVortIdxThere];
                            Vector3 rVorticityThere = rVortonThere.vorticity;

                            Vector3 vortDiff = rVorticityHere - rVorticityThere;
                            Vector3 exchange = 2.0f * mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles.

                            mVortons[rVortIdxHere].vorticity  -= exchange;              // Make "here" vorticity a little closer to "there".
                            mVortons[rVortIdxThere].vorticity += exchange;              // Make "there" vorticity a little closer to "here".
                        }

                        // Diffuse vorticity with vortons in adjacent cells:
                        {
                            uint offsetXpY0Z0 = idx[0] + 1 + offsetY0Z0; // offset of adjacent cell in +X direction
                            for (int ivThere = 0; ivThere < ugVortRef[offsetXpY0Z0].list.Count; ++ivThere)
                            {                                            // For each vorton in the adjacent cell in +X direction...
                                int     rVortIdxThere   = ugVortRef[offsetXpY0Z0].list[ivThere];
                                Vorton  rVortonThere    = mVortons[rVortIdxThere];
                                Vector3 rVorticityThere = rVortonThere.vorticity;

                                Vector3 vortDiff = rVorticityHere - rVorticityThere;
                                Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles.

                                mVortons[rVortIdxHere].vorticity  -= exchange;       // Make "here" vorticity a little closer to "there".
                                mVortons[rVortIdxThere].vorticity += exchange;       // Make "there" vorticity a little closer to "here".
                            }
                        }

                        {
                            uint offsetX0YpZ0 = idx[0] + offsetYpZ0; // offset of adjacent cell in +Y direction
                            for (int ivThere = 0; ivThere < ugVortRef[offsetX0YpZ0].list.Count; ++ivThere)
                            {                                        // For each vorton in the adjacent cell in +Y direction...
                                int     rVortIdxThere   = ugVortRef[offsetX0YpZ0].list[ivThere];
                                Vorton  rVortonThere    = mVortons[rVortIdxThere];
                                Vector3 rVorticityThere = rVortonThere.vorticity;

                                Vector3 vortDiff = rVorticityHere - rVorticityThere;
                                Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles.

                                mVortons[rVortIdxHere].vorticity  -= exchange;       // Make "here" vorticity a little closer to "there".
                                mVortons[rVortIdxThere].vorticity += exchange;       // Make "there" vorticity a little closer to "here".
                            }
                        }

                        {
                            uint offsetX0Y0Zp = idx[0] + offsetY0Zp; // offset of adjacent cell in +Z direction
                            for (int ivThere = 0; ivThere < ugVortRef[offsetX0Y0Zp].list.Count; ++ivThere)
                            {                                        // For each vorton in the adjacent cell in +Z direction...
                                int     rVortIdxThere   = ugVortRef[offsetX0Y0Zp].list[ivThere];
                                Vorton  rVortonThere    = mVortons[rVortIdxThere];
                                Vector3 rVorticityThere = rVortonThere.vorticity;

                                Vector3 vortDiff = rVorticityHere - rVorticityThere;
                                Vector3 exchange = mViscosity * timeStep * vortDiff; // Amount of vorticity to exchange between particles.

                                mVortons[rVortIdxHere].vorticity  -= exchange;       // Make "here" vorticity a little closer to "there".
                                mVortons[rVortIdxThere].vorticity += exchange;       // Make "there" vorticity a little closer to "here".
                            }
                        }

                        // Dissipate vorticity.  See notes in header comment.
                        mVortons[rVortIdxHere].vorticity -= mViscosity * timeStep * mVortons[rVortIdxHere].vorticity;   // Reduce "here" vorticity.
                    }
                }
            }
        }
    }
Example #6
0
 public void AddVorton(Vorton vorton)
 {
     mVortons.Add(vorton);
 }
Example #7
0
 public Vorton(Vorton that)
 {
     mPosition  = that.mPosition;
     mVorticity = that.mVorticity;
     mRadius    = that.mRadius;
 }
    void AssignVorticity(float fMagnitude, uint numVortonsMax, IVorticityDistribution vorticityDistribution)
    {
        Vector3 vDimensions = vorticityDistribution.GetDomainSize(); // length of each side of grid box
        Vector3 vCenter = (vorticityDistribution).GetCenter(); // Center of vorticity distribution
        Vector3 vMin = (vCenter - 0.5f * vDimensions) ; // Minimum corner of box containing vortons
        Vector3 vMax = (vMin + vDimensions) ; // Maximum corner of box containing vortons
        UniformGridGeometry skeleton = new UniformGridGeometry(numVortonsMax, vMin, vMax, true ) ;
        // number of grid cells in each direction of virtual uniform grid
        int[] numCells = {   (int)Mathf.Max( 1 , skeleton.GetNumCells(0))
                         ,   (int)Mathf.Max( 1 , skeleton.GetNumCells(1))
                         ,   (int)Mathf.Max( 1 , skeleton.GetNumCells(2)) };

        // Total number of cells should be as close to numVortonsMax as possible without going over.
        // Worst case allowable difference would be numVortonsMax=7 and numCells in each direction is 1 which yields a ratio of 1/7.
        // But in typical situations, the user would like expect total number of virtual cells to be closer to numVortonsMax than that.
        // E.g. if numVortonsMax=8^3=512 somehow yielded numCells[0]=numCells[1]=numCells[2]=7 then the ratio would be 343/512~=0.67.
        while (numCells[0] * numCells[1] * numCells[2] > numVortonsMax)
        {   // Number of cells is excessive.
            // This can happen when the trial number of cells in any direction is less than 1 -- then the other two will likely be too large.
            numCells[0] = (int)Mathf.Max(1, numCells[0] / 2);
            numCells[1] = (int)Mathf.Max(1, numCells[1] / 2);
            numCells[2] = (int)Mathf.Max(1, numCells[2] / 2);
        }

        float[] oneOverN = { 1.0f / (float)(numCells[0]), 1.0f / (float)(numCells[1]), 1.0f / (float)(numCells[2]) };
        Vector3 gridCellSize = new Vector3(vDimensions.x * oneOverN[0] , vDimensions.y * oneOverN[1], vDimensions.z * oneOverN[2] ) ;
        float vortonRadius = Mathf.Pow(gridCellSize.x * gridCellSize.y * gridCellSize.z, 1.0f / 3.0f) * 0.5f;
        if (0.0f == vDimensions.z)
        {   // z size is zero, so domain is 2D.
            vortonRadius = Mathf.Pow(gridCellSize.x * gridCellSize.y, 0.5f) * 0.5f;
        }
        Vector3 vNoise = (0.0f * gridCellSize) ;

        //-----------------------------------------------------------------------
        // Iterate through each point in a uniform grid.
        // If probe position is inside vortex core, add a vorton there.
        // This loop could be rewritten such that it only visits points inside the core,
        // but this loop structure can readily be reused for a wide variety of configurations.
        Vector3 position = new Vector3(0.0f, 0.0f, 0.0f); // vorton position
        int[] index = new int[3]; // index of each position visited

        for (index[2] = 0; index[2] < numCells[2]; ++index[2])
        {   // For each z-coordinate...
            position.z = ((float)(index[2]) + 0.25f) * gridCellSize.z + vMin.z;
            for (index[1] = 0; index[1] < numCells[1]; ++index[1])
            {   // For each y-coordinate...
                position.y = ((float)(index[1]) + 0.25f) * gridCellSize.y + vMin.y;
                for (index[0] = 0; index[0] < numCells[0]; ++index[0])
                {   // For each x-coordinate...
                    position.x = ((float)(index[0]) + 0.25f) * gridCellSize.x + vMin.x;
                    position += Random.Range(-1, 1) * (vNoise);
                    Vector3 vorticity = Vector3.zero;
                    vorticityDistribution.AssignVorticity(ref vorticity, position, vCenter);
                    Vorton vorton = new Vorton(position, vorticity * fMagnitude, vortonRadius);
                    if (vorticity.sqrMagnitude > global.GlobalVar.sTiny)
                    {   // Vorticity is significantly non-zero.
                        mVortonSim.AddVorton(vorton);
                    }
                }
            }
        }
        //-----------------------------------------------------------------------
    }
Example #9
0
 public Vorton( Vorton that )
 {
     mPosition = that.mPosition;
     mVorticity = that.mVorticity;
     mRadius = that.mRadius;
 }