/// <summary> /// velocity verlet routine to propagate the particle ensemble /// </summary> /// <param name="Height"></param> /// <param name="Width"></param> /// <param name="pExternalField"></param> public void VelocityVerletPropagation(ExternalField pExternalField) { int i, kk; double V = 0.0, T = 0.0, dt, pxnew, pynew, factor; AllPositionsUnchangedFromLastStep = true; //BoxWidth = Width; //BoxHeight = Height; if (NumberOfParticlesChangedFlag) { NumberOfParticlesChangedFlag = false; if (NumberOfParticlesIsGreaterFlag) { for (kk = 0; kk < NumberOfForceFieldObjects; ++kk) { // calculate the ij energy terms for particle set including the new ones GetForceFieldObject(kk).UpdateEnergyTerms(this); } } } else { // Timestep = 1.0/(double)ofGetFrameRate(); Timestep = 0.005; dt = Timestep; // increment ParticleEnsemble Private data member step ++step; if (BerendsenThermostat) { // Berendsen Thermostat BerendsenVelocityRescaling(); } // this loop uses verlet scheme (VV) to propagate the positions forward one step for (i = 0; i < NumberOfParticles; ++i) { SetLastXParticlePosition(i, GetXParticlePosition(i)); SetLastYParticlePosition(i, GetYParticlePosition(i)); factor = 0.5 * dt * dt / GetParticleMass(i); pxnew = GetXParticlePosition(i) + GetXParticleVelocity(i) * dt + GetXParticleForce(i) * factor; pynew = GetYParticlePosition(i) + GetYParticleVelocity(i) * dt + GetYParticleForce(i) * factor; if (pxnew > GetParticleRadius(i) && pxnew < (BoxWidth - GetParticleRadius(i))) { // this the standard VV code here SetXParticlePosition(i, pxnew); } else { // this is to reflect off the walls; added by DRG in lieu of soft walls to improve real time stability... not part of a standard VV scheme SetXParticlePosition(i, GetLastXParticlePosition(i)); SetXParticleVelocity(i, -1.0 * GetXParticleVelocity(i)); SetWasReflectedByWall(i, true); calculateParticleVelocitiesInXWallFrame(i); } if (pynew > GetParticleRadius(i) && pynew < (BoxHeight - GetParticleRadius(i))) { // this the standard VV code here SetYParticlePosition(i, pynew); } else { // this is to reflect off the walls; added by DRG in lieu of soft walls to improve real time stability... not part of a standard VV scheme SetYParticlePosition(i, GetLastYParticlePosition(i)); SetYParticleVelocity(i, -1.0 * GetYParticleVelocity(i)); SetWasReflectedByWall(i, true); calculateParticleVelocitiesInYWallFrame(i); } Particles[i].GridSector.GetSector(Particles[i].Position); } // check whether all the positions are changed from the last step for (i = 0; i < NumberOfParticles; ++i) { if (GetYParticlePosition(i) != GetLastYParticlePosition(i) || GetXParticlePosition(i) != GetLastXParticlePosition(i)) { AllPositionsUnchangedFromLastStep = false; } } if (AllPositionsUnchangedFromLastStep) { // this is a stability measure; if the frame is frozen wrt to the previous frame, // adjust particle positions to eliminate overlap - this can cause the sim to freeze EliminateParticleOverlap(BoxHeight, BoxWidth); for (i = 0; i < NumberOfParticles; ++i) { // then we zero out the forces and velocities & repropagate the positions SetXParticleForce(i, 0.0); SetYParticleForce(i, 0.0); SetLastXParticlePosition(i, GetXParticlePosition(i)); SetLastYParticlePosition(i, GetYParticlePosition(i)); SetXParticlePosition(i, GetXParticlePosition(i) + GetXParticleVelocity(i) * dt + (GetXParticleForce(i) / GetParticleMass(i)) * dt * dt * 0.5); SetYParticlePosition(i, GetYParticlePosition(i) + GetYParticleVelocity(i) * dt + (GetYParticleForce(i) / GetParticleMass(i)) * dt * dt * 0.5); Particles[i].GridSector.GetSector(Particles[i].Position); } AllPositionsUnchangedFromLastStep = false; } UpdateInterParticleSeparations(); if (pExternalField != null) { pExternalField.CalculateForceField(this); } if (GetForceFieldObject(0).ForceFieldType == "HardSphereForceField") { GetForceFieldObject(0).CalculateForceField(this); } else { for (i = 0; i < NumberOfParticles; ++i) { // save the present forces to t-1 vectors SetLastXParticleForce(i, GetXParticleForce(i)); SetLastYParticleForce(i, GetYParticleForce(i)); } // zero out the force vectors & potential energy ZeroXForces(); ZeroYForces(); PotentialEnergy = 0.0; for (kk = 0; kk < NumberOfForceFieldObjects; ++kk) { // calculate & set the forces at the new positions GetForceFieldObject(kk).CalculateForceField(this); } for (i = 0; i < NumberOfParticles; ++i) { // use VV scheme to propagate the velocities forward factor = dt * 0.5 / GetParticleMass(i); SetXParticleVelocity(i, GetXParticleVelocity(i) + (GetXParticleForce(i) + GetLastXParticleForce(i)) * factor); SetYParticleVelocity(i, GetYParticleVelocity(i) + (GetYParticleForce(i) + GetLastYParticleForce(i)) * factor); } // Update the ensemble velocity autocorrelation function //if (m_FFTenabled) //{ // UpdateVelocityAutoCorrelationFunction(); // FFTVelocityAutoCorrelationFunction(); //} // see whether any collisions occurred DetermineIfCollisionsOccurred(); } } }
public static void LoadConfig(string filename) { #region Load the actual config if (File.Exists(filename)) { RC.WriteLine(ConsoleThemeColor.TitleText1, "Loading config '" + filename + "'"); XmlDocument doc = new XmlDocument(); doc.Load(filename); m_Options.Load(doc.DocumentElement); } #endregion #region Setup The Field Image m_CompositeFieldImage.Bounds = m_Options.Kinect.Bounds; int i = 0; foreach (DS.Simulation.CompositeFieldImage.KinectFieldImage field in m_CompositeFieldImage.Images) { field.X = m_Options.Kinect.Cameras[i].X; field.Y = m_Options.Kinect.Cameras[i++].Y; } #endregion #region Setup The Particle Simulation double gradScaleFactor = 1000.0; double MinRad = 10.0; double MaxRad = 30.0; List<string> FFtype = new List<string>(new string[] { "SoftSpheres", "ExternalField" }); ParticleStaticObjects.AtomPropertiesDefinition.Clear(); ParticleStaticObjects.AtomPropertiesDefinition.AddParticleDefinition("A", 1, new Color3(0.0390625f, 0.1953125f, 0.99609375f), 0, 20); // neon blue 0xc00A32FF ParticleStaticObjects.AtomPropertiesDefinition.AddParticleDefinition("B", 4, new Color3(1f, 0.03921569f, 0.1960784f), 1, 49); // red 0xc0FF0A32 ParticleStaticObjects.AtomPropertiesDefinition.AddParticleDefinition("C", 6, new Color3(0.1960784f, 0.03921569f, 1f), 2, 45); // purple 0xc0320AFF ParticleStaticObjects.AtomPropertiesDefinition.AddParticleDefinition("D", 9.2, new Color3(0.1490196f, 0.8470589f, 1f), 3, 43); // sky blue 0xc026D8FF // 0xc032FF0A, 3, 43); // green ParticleStaticObjects.AtomPropertiesDefinition.AddParticleDefinition("E", 12.6, new Color3(1f, 0.1960784f, 0.03921569f), 4, 38); // orange 0xc0FF320A ParticleStaticObjects.ReSeedRandom(42); m_Ensemble = new ParticleEnsemble(1, MinRad, MaxRad, FFtype, ArtworkStaticObjects.CompositeFieldImage.Height, ArtworkStaticObjects.CompositeFieldImage.Width, gradScaleFactor); m_ExternalField = new ExternalField(m_Ensemble, ArtworkStaticObjects.CompositeFieldImage); for (int j = 0; j < ParticleStaticObjects.AtomPropertiesDefinition.Count; j++) { ParticleStaticObjects.AtomPropertiesDefinition.SetAttractiveOrRepulsive(j, Options.Simulation.ParticleTypes[j].AttractiveOrRepulsive); ParticleStaticObjects.AtomPropertiesDefinition.SetEnabled(j, Options.Simulation.ParticleTypes[j].IsEnabled); ParticleStaticObjects.AtomPropertiesDefinition.SetSound(j, Options.Simulation.ParticleTypes[j].IsSoundOn); } m_Ensemble.BerendsenThermostatCoupling = Options.Simulation.BerendsenThermostatCoupling; m_Ensemble.EquilibriumTemperature = Options.Simulation.EquilibriumTemperature; m_Ensemble.GradientScaleFactor = Options.Simulation.GradientScaleFactor; int newNumber = Options.Simulation.NumberOfParticles; while (ArtworkStaticObjects.Ensemble.NumberOfParticles < newNumber) { ArtworkStaticObjects.Ensemble.InitializeOneNewParticle(); } while (ArtworkStaticObjects.Ensemble.NumberOfParticles > newNumber) { ArtworkStaticObjects.Ensemble.Particles.Pop(); } m_Ensemble.ParticleScale = Options.Simulation.ParticleScale; m_Ensemble.PotentialEnergy = Options.Simulation.PotentialEnergy; //ParticleStaticObjects.AtomPropertiesDefinition.ToggleAttractiveOrRepulsive(0); #endregion }