예제 #1
0
 /// <summary>
 /// Copy a Particle
 /// </summary>
 /// <param name="mass"></param>
 public Particle(Particle particle)
 {
     mass         = particle.mass;
     position     = particle.position;
     momentum     = particle.momentum;
     interactions = particle.interactions;
 }
예제 #2
0
        /// <summary>
        /// Allow timeInterval to pass for the Particle with given netForce applied.
        /// Recommend putting Particle into a PhysicalSystem and using a PhysicalSystem.Iterate() instead.
        /// </summary>
        /// <param name="timeInterval"></param>
        /// <param name="netForce"></param>
        public void Iterate(Time timeInterval, Force netForce)
        {
            Momentum changeInMomentum = timeInterval * netForce;

            Displacement changeInPosition = timeInterval * Velocity(momentum + changeInMomentum / 2.0);

            momentum += changeInMomentum;
            position += changeInPosition;
        }
예제 #3
0
        /// <summary>
        /// Update the positions and momenta of all particles in the system using Runge-Kutta method...
        /// Does not seem to be working correctly. Leave private until debugged.
        /// </summary>
        /// <param name="timeInterval">The amount of time passing during this iteration</param>
        private void RK4Iterate(Time timeInterval)
        {
            List <Task> tasks = new List <Task>();

            // store temporary particle data for Runge-Kutta method
            Particle[] virtualParticles = new Particle[particles.Count];
            Momentum[,] momenta           = new Momentum[particles.Count, 4];
            Displacement[,] displacements = new Displacement[particles.Count, 4];

            // initialize virtualParticles
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(InitializeParticle(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // first iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 0));
            }
            Task.WaitAll(tasks.ToArray());

            // update before 2nd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(UpdateParticleBefore2ndOr3rdIteration(particleIndex, 0));
            }
            Task.WaitAll(tasks.ToArray());

            // 2nd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 1));
            }
            Task.WaitAll(tasks.ToArray());

            // update before 3rd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(UpdateParticleBefore2ndOr3rdIteration(particleIndex, 1));
            }
            Task.WaitAll(tasks.ToArray());

            // 3rd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 2));
            }
            Task.WaitAll(tasks.ToArray());

            // update before 4th iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(UpdateParticleBefore4thIteration(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // 4th iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 3));
            }
            Task.WaitAll(tasks.ToArray());

            // update actual particles using the Runge-Kutta coefficients
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(UpdateParticleUsingRungeKuttaCoefficients(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            async Task InitializeParticle(int particleIndex)
            {
                virtualParticles[particleIndex] = new Particle(particles[particleIndex]);
                for (int iterationNumber = 0; iterationNumber < 4; iterationNumber++)
                {
                    momenta[particleIndex, iterationNumber] = new Momentum();
                }
            }

            async Task CalculateRungeKuttaCoefficients(int particleIndex, int iterationNumber)
            {
                displacements[particleIndex, iterationNumber] =
                    timeInterval * particles[particleIndex].Velocity();
                foreach (Interaction interaction in virtualParticles[particleIndex].interactions)
                {
                    momenta[particleIndex, iterationNumber] +=
                        timeInterval * interaction.InteractionForce(virtualParticles[particleIndex], interaction.B);
                }
            }

            async Task UpdateParticleBefore2ndOr3rdIteration(int particleIndex, int iterationJustFinished)
            {
                virtualParticles[particleIndex]           = new Particle(particles[particleIndex]);
                virtualParticles[particleIndex].momentum +=
                    momenta[particleIndex, iterationJustFinished];       // / 2.0;
                virtualParticles[particleIndex].position +=
                    displacements[particleIndex, iterationJustFinished]; // / 2.0;
            }

            async Task UpdateParticleBefore4thIteration(int particleIndex)
            {
                virtualParticles[particleIndex]           = new Particle(particles[particleIndex]);
                virtualParticles[particleIndex].momentum +=
                    momenta[particleIndex, 2];
                virtualParticles[particleIndex].position +=
                    displacements[particleIndex, 2];
            }

            async Task UpdateParticleUsingRungeKuttaCoefficients(int particleIndex)
            {
                //particles[particleIndex].position += (displacements[particleIndex, 0] +
                //    2.0 * displacements[particleIndex, 1] + 2.0 * displacements[particleIndex, 2] +
                //    displacements[particleIndex, 3]) / 6.0;
                //particles[particleIndex].momentum += (momenta[particleIndex, 0] +
                //    2.0 * momenta[particleIndex, 1] + 2.0 * momenta[particleIndex, 2] +
                //    momenta[particleIndex, 3]) / 6.0;
                particles[particleIndex].position += (displacements[particleIndex, 0] +
                                                      displacements[particleIndex, 1]) / 2.0;
                particles[particleIndex].momentum += (momenta[particleIndex, 0] +
                                                      momenta[particleIndex, 1]) / 2.0;
            }
        }
예제 #4
0
        /// <summary>
        /// Heun's method for numerical integration
        /// </summary>
        /// <param name="timeStep"></param>
        private void HeunIntegration(Time timeStep)
        {
            List <Task> tasks = new List <Task>();

            // store temporary particle data for Runge-Kutta method
            Displacement[] initialPositions = new Displacement[particles.Count];
            Momentum[]     initialMomenta   = new Momentum[particles.Count];
            Momentum[,] momenta           = new Momentum[particles.Count, 2];
            Displacement[,] displacements = new Displacement[particles.Count, 2];

            // store initial condition
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(StoreInitialConditions(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // first iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 0));
            }
            Task.WaitAll(tasks.ToArray());

            // update particles based on linear estimate
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(LinearUpdate(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // 2nd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(CalculateRungeKuttaCoefficients(particleIndex, 1));
            }
            Task.WaitAll(tasks.ToArray());

            // update actual particles using the Runge-Kutta coefficients
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(UpdateParticles(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            async Task StoreInitialConditions(int particleIndex)
            {
                initialPositions[particleIndex] = particles[particleIndex].position;
                initialMomenta[particleIndex]   = particles[particleIndex].momentum;
            }

            async Task CalculateRungeKuttaCoefficients(int particleIndex, int iterationNumber)
            {
                displacements[particleIndex, iterationNumber] =
                    timeStep * particles[particleIndex].Velocity();
                Force netForce = new Force();

                foreach (Interaction interaction in particles[particleIndex].interactions)
                {
                    netForce += interaction.InteractionForce();
                }
                momenta[particleIndex, iterationNumber] = timeStep * netForce;
            }

            async Task LinearUpdate(int particleIndex)
            {
                particles[particleIndex].position += timeStep * particles[particleIndex].Velocity(
                    particles[particleIndex].momentum + momenta[particleIndex, 0] / 2.0);
                particles[particleIndex].momentum += momenta[particleIndex, 0];
            }

            async Task UpdateParticles(int particleIndex)
            {
                particles[particleIndex].position = initialPositions[particleIndex] +
                                                    (displacements[particleIndex, 0] + displacements[particleIndex, 1]) / 2.0;
                particles[particleIndex].momentum = initialMomenta[particleIndex] +
                                                    (momenta[particleIndex, 0] + momenta[particleIndex, 1]) / 2.0;
            }
        }
예제 #5
0
        /// <summary>
        /// Update the positions and momenta of all particles in the system
        /// using the 2nd-order Runge-Kutta method.
        /// Doesn't perform as well as NotQuiteRK2(). Am I interpretting the Runge-Kutta method incorrectly?
        /// </summary>
        /// <param name="timeInterval">The amount of time passing during this iteration</param>
        private void RK2Iterate(Time timeInterval)
        {
            List <Task> tasks = new List <Task>();

            // store temporary particle data for Runge-Kutta method
            Displacement[] initialPositions = new Displacement[particles.Count];
            Momentum[]     initialMomenta   = new Momentum[particles.Count];
            Momentum[,] momenta           = new Momentum[particles.Count, 2];
            Displacement[,] displacements = new Displacement[particles.Count, 2];

            // store initial condition
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(StoreInitialConditions(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // first iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(FirstIteration(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            // 2nd iteration
            for (int particleIndex = 0; particleIndex < particles.Count; particleIndex++)
            {
                tasks.Add(SecondIteration(particleIndex));
            }
            Task.WaitAll(tasks.ToArray());

            async Task StoreInitialConditions(int particleIndex)
            {
                initialPositions[particleIndex] = particles[particleIndex].position;
                initialMomenta[particleIndex]   = particles[particleIndex].momentum;
            }

            async Task FirstIteration(int particleIndex)
            {
                Force netForce = new Force();

                foreach (Interaction interaction in particles[particleIndex].interactions)
                {
                    netForce += interaction.InteractionForce();
                }
                // The first iteration in RK2 only moves a half step.
                Momentum changeInMomentum = timeInterval * netForce / 2.0;

                particles[particleIndex].position += timeInterval *
                                                     particles[particleIndex].Velocity(
                    particles[particleIndex].momentum + changeInMomentum / 2.0) / 2.0;
                particles[particleIndex].momentum += changeInMomentum;
            }

            async Task SecondIteration(int particleIndex)
            {
                Force netForce = new Force();

                foreach (Interaction interaction in particles[particleIndex].interactions)
                {
                    netForce += interaction.InteractionForce();
                }
                Momentum changeInMomentum = timeInterval * netForce;

                particles[particleIndex].position = initialPositions[particleIndex] + timeInterval *
                                                    particles[particleIndex].Velocity(
                    particles[particleIndex].momentum + changeInMomentum / 2.0);
                particles[particleIndex].momentum = initialMomenta[particleIndex] + changeInMomentum;
            }
        }
예제 #6
0
 /// <summary>
 /// The Velocity of this Particle given a momentum
 /// </summary>
 /// <returns>The Velocity of this Particle given a momentum</returns>
 public Velocity Velocity(Momentum p)
 {
     return(p / mass);
 }