Converted foreach into for loops in the PartSim class.
Converted foreach into for loops in the PartSim class.

--- a/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
+++ b/KerbalEngineer/VesselSimulator/AttachNodeSim.cs
@@ -19,42 +19,44 @@
 
 #region Using Directives
 
-using System;
-using System.Text;
-
 #endregion
 
 namespace KerbalEngineer.VesselSimulator
 {
-    internal class AttachNodeSim
+    using System;
+    using System.Text;
+
+    internal class AttachNodeSim : Pool<AttachNodeSim>
     {
         public PartSim attachedPartSim;
         public String id;
         public AttachNode.NodeType nodeType;
 
-        public AttachNodeSim(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
-        {
-            this.attachedPartSim = partSim;
-            this.nodeType = newNodeType;
-            this.id = newId;
-        }
-
         public void DumpToBuffer(StringBuilder buffer)
         {
-            if (this.attachedPartSim == null)
+            if (attachedPartSim == null)
             {
                 buffer.Append("<staged>:<n>");
             }
             else
             {
-                buffer.Append(this.attachedPartSim.name);
+                buffer.Append(attachedPartSim.name);
                 buffer.Append(":");
-                buffer.Append(this.attachedPartSim.partId);
+                buffer.Append(attachedPartSim.partId);
             }
             buffer.Append("#");
-            buffer.Append(this.nodeType);
+            buffer.Append(nodeType);
             buffer.Append(":");
-            buffer.Append(this.id);
+            buffer.Append(id);
+        }
+
+        public AttachNodeSim Initialise(PartSim partSim, String newId, AttachNode.NodeType newNodeType)
+        {
+            attachedPartSim = partSim;
+            nodeType = newNodeType;
+            id = newId;
+
+            return this;
         }
     }
 }

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -41,7 +41,7 @@
         public Vector3 thrustVec;
         private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
 
-        public EngineSim Init(PartSim theEngine,
+        public EngineSim Initialise(PartSim theEngine,
             double atmosphere,
             float machNumber,
             float maxFuelFlow,
@@ -102,47 +102,22 @@
                 flowRate = GetFlowRate(thrust, isp);
             }
 
-            if (SimManager.logOutput)
-            {
-                buffer = new StringBuilder(1024);
-                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
-            }
-
-            float flowMass = 0f;
-            foreach (Propellant propellant in propellants)
-            {
+            float flowMass = 0.0f;
+
+            for (int i = 0; i < propellants.Count; ++i)
+            {
+                Propellant propellant = propellants[i];
                 flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
-            }
-
-            foreach (Propellant propellant in propellants)
-            {
-                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
-                {
-                    continue;
-                }
 
                 double consumptionRate = propellant.ratio * flowRate / flowMass;
-                if (SimManager.logOutput)
-                {
-                    buffer.AppendFormat("Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate);
-                }
                 resourceConsumptions.Add(propellant.id, consumptionRate);
             }
 
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print(buffer);
-            }
-
-            appliedForces.Clear();
             double thrustPerThrustTransform = thrust / thrustTransforms.Count;
-            foreach (Transform thrustTransform in thrustTransforms)
-            {
+            for (int i = 0; i < thrustTransforms.Count; ++i)
+            {
+                Transform thrustTransform = thrustTransforms[i];
+
                 Vector3d direction = thrustTransform.forward.normalized;
                 Vector3d position = thrustTransform.position;
                 appliedForces.Add(new AppliedForce(direction * thrustPerThrustTransform, position));
@@ -220,8 +195,9 @@
             // A dictionary to hold a set of parts for each resource
             Dictionary<int, HashSet<PartSim>> sourcePartSets = new Dictionary<int, HashSet<PartSim>>();
 
-            foreach (int type in resourceConsumptions.Types)
-            {
+            for (int i = 0; i < resourceConsumptions.Types.Count; ++i)
+            {
+                int type = resourceConsumptions.Types[i];
                 HashSet<PartSim> sourcePartSet = null;
                 switch (ResourceContainer.GetResourceFlowMode(type))
                 {
@@ -235,8 +211,10 @@
                         break;
 
                     case ResourceFlowMode.ALL_VESSEL:
-                        foreach (PartSim aPartSim in allParts)
-                        {
+                        for (int j = 0; j < allParts.Count; ++j)
+                        {
+                            PartSim aPartSim = allParts[j];
+
                             if (aPartSim.resources[type] > SimManager.RESOURCE_MIN && aPartSim.resourceFlowStates[type] != 0)
                             {
                                 if (sourcePartSet == null)
@@ -253,9 +231,10 @@
                         Dictionary<int, HashSet<PartSim>> stagePartSets = new Dictionary<int, HashSet<PartSim>>();
                         int maxStage = -1;
 
-                        //Logger.Log(type);
-                        foreach (PartSim aPartSim in allParts)
-                        {
+                        for (int j = 0; j < allParts.Count; ++j)
+                        {
+                            PartSim aPartSim = allParts[j];
+
                             if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0)
                             {
                                 continue;
@@ -275,10 +254,10 @@
                             sourcePartSet.Add(aPartSim);
                         }
 
-                        for (int i = 0; i <= maxStage; i++)
+                        for (int j = 0; j <= maxStage; j++)
                         {
                             HashSet<PartSim> stagePartSet;
-                            if (stagePartSets.TryGetValue(i, out stagePartSet) && stagePartSet.Count > 0)
+                            if (stagePartSets.TryGetValue(j, out stagePartSet) && stagePartSet.Count > 0)
                             {
                                 sourcePartSet = stagePartSet;
                             }
@@ -322,8 +301,10 @@
             }
 
             // If we don't have sources for all the needed resources then return false without setting up any drains
-            foreach (int type in resourceConsumptions.Types)
-            {
+            for(int i = 0; i < resourceConsumptions.Types.Count; ++i)
+            {
+                int type = resourceConsumptions.Types[i];
+
                 if (!sourcePartSets.ContainsKey(type))
                 {
                     if (SimManager.logOutput)
@@ -337,8 +318,10 @@
             }
 
             // Now we set the drains on the members of the sets and update the draining parts set
-            foreach (int type in resourceConsumptions.Types)
-            {
+            for (int i = 0; i < resourceConsumptions.Types.Count; ++i)
+            {
+                int type = resourceConsumptions.Types[i];
+
                 HashSet<PartSim> sourcePartSet = sourcePartSets[type];
                 // Loop through the members of the set 
                 double amount = resourceConsumptions[type] / sourcePartSet.Count;

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -34,11 +34,11 @@
 {
     using CompoundParts;
 
-    public class PartSim
+    public class PartSim : Pool<PartSim>
     {
         private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
         public Vector3d centerOfMass;
-        public double baseMass = 0d;
+        public double baseMass;
         public double cost;
         public int decoupledInStage;
         public bool fuelCrossFeed;
@@ -71,8 +71,47 @@
         public String vesselName;
         public VesselType vesselType;
 
-        public PartSim(Part thePart, int id, double atmosphere, LogMsg log)
-        {
+        private static void Reset(PartSim partSim)
+        {
+            partSim.attachNodes.Clear();
+            partSim.fuelTargets.Clear();
+            partSim.resourceDrains.Reset();
+            partSim.resourceFlowStates.Reset();
+            partSim.resources.Reset();
+            partSim.baseMass = 0.0;
+            partSim.startMass = 0.0;
+            partSim.centerOfMass = Vector3d.zero;
+            partSim.cost = 0.0;
+            partSim.decoupledInStage = 0;
+            partSim.fuelCrossFeed = false;
+            partSim.hasModuleEngines = false;
+            partSim.hasModuleEnginesFX = false;
+            partSim.hasMultiModeEngine = false;
+            partSim.hasVessel = false;
+            partSim.initialVesselName = null;
+            partSim.inverseStage = 0;
+            partSim.isDecoupler = false;
+            partSim.isEngine = false;
+            partSim.isFuelLine = false;
+            partSim.isFuelTank = false;
+            partSim.isLanded = false;
+            partSim.isNoPhysics = false;
+            partSim.isSepratron = false;
+            partSim.localCorrectThrust = false;
+            partSim.name = null;
+            partSim.noCrossFeedNodeKey = null;
+            partSim.parent = null;
+            partSim.parentAttach = AttachModes.SRF_ATTACH;
+            partSim.part = null;
+            partSim.partId = 0;
+            partSim.vesselName = null;
+            partSim.vesselType = VesselType.Base;
+        }
+
+        public PartSim Initialise(Part thePart, int id, double atmosphere, LogMsg log)
+        {
+            Reset(this);
+
             this.part = thePart;
             this.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
             this.partId = id;
@@ -97,13 +136,11 @@
             this.cost = this.part.GetCostWet();
 
             // Work out if the part should have no physical significance
-            this.isNoPhysics = this.part.HasModule<LaunchClamp>() ||
-                               this.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
-                               this.part.PhysicsSignificance == 1;
-
-            if (!this.isNoPhysics)
-            {
-                this.baseMass = this.part.mass;
+            this.isNoPhysics = this.part.HasModule<LaunchClamp>();
+
+            if (isNoPhysics == false)
+            {
+                baseMass = part.mass;
             }
 
             if (SimManager.logOutput)
@@ -111,8 +148,10 @@
                 MonoBehaviour.print((this.isNoPhysics ? "Ignoring" : "Using") + " part.mass of " + this.part.mass);
             }
 
-            foreach (PartResource resource in this.part.Resources)
-            {
+            for (int i = 0; i < part.Resources.Count; ++i)
+            {
+                PartResource resource = part.Resources[i];
+
                 // Make sure it isn't NaN as this messes up the part mass and hence most of the values
                 // This can happen if a resource capacity is 0 and tweakable
                 if (!Double.IsNaN(resource.amount))
@@ -152,6 +191,8 @@
             {
                 MonoBehaviour.print("Created " + this.name + ". Decoupled in stage " + this.decoupledInStage);
             }
+
+            return this;
         }
 
         public ResourceContainer Resources
@@ -185,8 +226,12 @@
                 // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                 string mode = this.part.GetModule<MultiModeEngine>().mode;
 
-                foreach (ModuleEnginesFX engine in this.part.GetModules<ModuleEnginesFX>())
-                {
+                List<ModuleEnginesFX> engines = part.GetModules<ModuleEnginesFX>();
+
+                for (int i = 0; i < engines.Count; ++i)
+                {
+                    ModuleEnginesFX engine = engines[i];
+
                     if (engine.engineID == mode)
                     {
                         if (log != null)
@@ -196,7 +241,7 @@
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
-                        EngineSim engineSim = EngineSim.GetPoolObject().Init(this,
+                        EngineSim engineSim = EngineSim.GetPoolObject().Initialise(this,
                             atmosphere,
                             (float)mach,
                             engine.maxFuelFlow,
@@ -221,8 +266,10 @@
             {
                 if (this.hasModuleEngines)
                 {
-                    foreach (ModuleEngines engine in this.part.GetModules<ModuleEngines>())
-                    {
+                    List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
+                    for (int i = 0; i < engines.Count; ++i)
+                    {
+                        ModuleEngines engine = engines[i];
                         if (log != null)
                         {
                             log.buf.AppendLine("Module: " + engine.moduleName);
@@ -230,7 +277,7 @@
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
-                        EngineSim engineSim = EngineSim.GetPoolObject().Init(this,
+                        EngineSim engineSim = EngineSim.GetPoolObject().Initialise(this,
                             atmosphere,
                             (float)mach,
                             engine.maxFuelFlow,
@@ -266,8 +313,10 @@
             }
 
             Vector3 thrustvec = Vector3.zero;
-            foreach (Transform trans in thrustTransforms)
-            {
+            for (int i = 0; i < thrustTransforms.Count; ++i)
+            {
+                Transform trans = thrustTransforms[i];
+
                 if (log != null)
                 {
                     log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
@@ -320,9 +369,12 @@
                 log.buf.AppendLine("SetupAttachNodes for " + this.name + ":" + this.partId + "");
             }
 
-            this.attachNodes.Clear();
-            foreach (AttachNode attachNode in this.part.attachNodes)
-            {
+            attachNodes.Clear();
+
+            for (int i = 0; i < part.attachNodes.Count; ++i)
+            {
+                AttachNode attachNode = part.attachNodes[i];
+
                 if (log != null)
                 {
                     log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
@@ -338,7 +390,7 @@
                             log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
                         }
 
-                        this.attachNodes.Add(new AttachNodeSim(attachedSim, attachNode.id, attachNode.nodeType));
+                        attachNodes.Add(AttachNodeSim.GetPoolObject().Initialise(attachedSim, attachNode.id, attachNode.nodeType));
                     }
                     else
                     {
@@ -350,8 +402,10 @@
                 }
             }
 
-            foreach (Part p in this.part.fuelLookupTargets)
-            {
+            for (int i = 0; i < part.fuelLookupTargets.Count; ++i)
+            {
+                Part p = part.fuelLookupTargets[i];
+
                 if (p != null)
                 {
                     PartSim targetSim;
@@ -469,9 +523,10 @@
             // Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
             // Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
             //MonoBehaviour.print("foreach fuel line");
-
-            foreach (PartSim partSim in this.fuelTargets)
-            {
+            for (int i = 0; i < fuelTargets.Count; ++i)
+            {
+                PartSim partSim = fuelTargets[i];
+
                 if (visited.Contains(partSim))
                 {
                     //if (log != null)
@@ -511,8 +566,10 @@
             if (this.fuelCrossFeed)
             {
                 //MonoBehaviour.print("foreach attach node");
-                foreach (AttachNodeSim attachSim in this.attachNodes)
-                {
+                for (int i = 0; i < attachNodes.Count; ++i)
+                {
+                    AttachNodeSim attachSim = attachNodes[i];
+
                     if (attachSim.attachedPartSim != null)
                     {
                         if (attachSim.nodeType == AttachNode.NodeType.Stack)
@@ -608,8 +665,10 @@
         public void RemoveAttachedParts(HashSet<PartSim> partSims)
         {
             // Loop through the attached parts
-            foreach (AttachNodeSim attachSim in this.attachNodes)
-            {
+            for (int i = 0; i < attachNodes.Count; ++i)
+            {
+                AttachNodeSim attachSim = attachNodes[i];
+
                 // If the part is in the set then "remove" it by clearing the PartSim reference
                 if (partSims.Contains(attachSim.attachedPartSim))
                 {
@@ -621,8 +680,10 @@
         public void DrainResources(double time)
         {
             //MonoBehaviour.print("DrainResources(" + name + ":" + partId + ", " + time + ")");
-            foreach (int type in this.resourceDrains.Types)
-            {
+            for (int i = 0; i < resourceDrains.Types.Count; ++i)
+            {
+                int type = resourceDrains.Types[i];
+
                 //MonoBehaviour.print("draining " + (time * resourceDrains[type]) + " " + ResourceContainer.GetResourceName(type));
                 this.resources.Add(type, -time * this.resourceDrains[type]);
                 //MonoBehaviour.print(ResourceContainer.GetResourceName(type) + " left = " + resources[type]);
@@ -634,8 +695,10 @@
             //MonoBehaviour.print("TimeToDrainResource(" + name + ":" + partId + ")");
             double time = double.MaxValue;
 
-            foreach (int type in this.resourceDrains.Types)
-            {
+            for (int i = 0; i < resourceDrains.Types.Count; ++i)
+            {
+                int type = resourceDrains.Types[i];
+
                 if (this.resourceDrains[type] > 0)
                 {
                     time = Math.Min(time, this.resources[type] / this.resourceDrains[type]);
@@ -686,9 +749,9 @@
         {
             double mass = this.baseMass;
 
-            foreach (int type in this.resources.Types)
-            {
-                mass += this.resources.GetResourceMass(type);
+            for (int i = 0; i < resources.Types.Count; ++i)
+            {
+                mass += this.resources.GetResourceMass(resources.Types[i]);
             }
 
             return mass;

--- a/KerbalEngineer/VesselSimulator/SimManager.cs
+++ b/KerbalEngineer/VesselSimulator/SimManager.cs
@@ -368,8 +368,8 @@
                 // This call doesn't ever fail at the moment but we'll check and return a sensible error for display
                 if (simulation.PrepareSimulation(parts, Gravity, Atmosphere, Mach, dumpTree, vectoredThrust))
                 {
-                    //ThreadPool.QueueUserWorkItem(RunSimulation, simulation);
-                    RunSimulation(simulation);
+                    ThreadPool.QueueUserWorkItem(RunSimulation, simulation);
+                    //RunSimulation(simulation);
                 }
                 else
                 {

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -32,10 +32,10 @@
 {
     using CompoundParts;
     using Extensions;
+    using Helpers;
 
     public class Simulation
     {
-        private const double STD_GRAVITY = 9.82;
         private const double SECONDS_PER_DAY = 86400;
         private readonly Stopwatch _timer = new Stopwatch();
         private List<EngineSim> activeEngines = new List<EngineSim>();
@@ -144,7 +144,9 @@
             activeEngines.Clear();
             drainingResources.Clear();
 
+            PartSim.ReleaseAll();
             EngineSim.ReleaseAll();
+            AttachNodeSim.ReleaseAll();
 
             // A dictionary for fast lookup of Part->PartSim during the preparation phase
             partSimLookup.Clear();
@@ -170,7 +172,7 @@
                 }
 
                 // Create the PartSim
-                PartSim partSim = new PartSim(part, partId, this.atmosphere, log);
+                PartSim partSim = PartSim.GetPoolObject().Initialise(part, partId, this.atmosphere, log);
 
                 // Add it to the Part lookup dictionary and the necessary lists
                 partSimLookup.Add(part, partSim);
@@ -504,7 +506,7 @@
                     // If we have drained anything and the masses make sense then add this step's deltaV to the stage total
                     if (resourceDrainTime > 0d && this.stepStartMass > this.stepEndMass && this.stepStartMass > 0d && this.stepEndMass > 0d)
                     {
-                        this.vecStageDeltaV += this.vecThrust * (float)((this.currentisp * STD_GRAVITY * Math.Log(this.stepStartMass / this.stepEndMass)) / this.simpleTotalThrust);
+                        this.vecStageDeltaV += this.vecThrust * (float)((this.currentisp * Units.GRAVITY * Math.Log(this.stepStartMass / this.stepEndMass)) / this.simpleTotalThrust);
                     }
 
                     // Update the active engines and resource drains for the next step
@@ -548,7 +550,7 @@
                 // Note: If the mass doesn't change then this is a divide by zero
                 if (this.stageStartMass != this.stepStartMass)
                 {
-                    stage.isp = stage.deltaV / (STD_GRAVITY * Math.Log(this.stageStartMass / this.stepStartMass));
+                    stage.isp = stage.deltaV / (Units.GRAVITY * Math.Log(this.stageStartMass / this.stepStartMass));
                 }
                 else
                 {

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ