Example #1
0
        private void CalculateFullThrustAndISP()
        {
            fullSimpleThrust     = 0;
            fullVecThrust        = Vector3.zero;
            fullStageFlowRate    = 0d;
            fullStageIspFlowRate = 0d;
            fullISP = 0;

            for (int i = 0; i < stageEngines.Count; i++)
            {
                EngineSim engine = stageEngines[i];

                fullSimpleThrust += engine.fullThrust;
                fullVecThrust    += ((float)engine.fullThrust * engine.thrustVec);

                fullStageFlowRate    += engine.MaxResourceConsumptions.Mass;
                fullStageIspFlowRate += engine.MaxResourceConsumptions.Mass * engine.isp;
            }

            if (fullStageFlowRate > 0 && fullStageIspFlowRate > 0)
            {
                fullISP = fullStageIspFlowRate / fullStageFlowRate;
            }
            else
            {
                fullISP = 0;
            }
        }
Example #2
0
        private void CalculateThrustAndISP()
        {
            // Reset all the values
            vecThrust       = Vector3.zero;
            vecActualThrust = Vector3.zero;
            totalVectoredExhaustVelocity       = Vector3.zero;
            totalActualVectoredExhaustVelocity = Vector3.zero;
            totalExhaustVelocity       = 0;
            totalActualExhaustVelocity = 0;
            simpleTotalThrust          = 0d;
            simpleActualTotalThrust    = 0d;
            totalStageThrust           = 0d;
            totalStageActualThrust     = 0d;
            totalStageFlowRate         = 0d;
            totalStageIspFlowRate      = 0d;
            totalStageThrustForce.Reset();

            // Loop through all the active engines totalling the thrust, actual thrust and mass flow rates
            // The thrust is totalled as vectors
            for (int i = 0; i < activeEngines.Count; ++i)
            {
                EngineSim engine = activeEngines[i];

                simpleTotalThrust       += engine.thrust;
                simpleActualTotalThrust += engine.actualThrust;
                vecThrust       += ((float)engine.thrust * engine.thrustVec);
                vecActualThrust += ((float)engine.actualThrust * engine.thrustVec);

                totalVectoredExhaustVelocity += engine.thrustVec * (float)((engine.isp * BasicDeltaV.GRAVITY) / engine.thrust);
                totalExhaustVelocity         += totalVectoredExhaustVelocity.magnitude;

                totalActualVectoredExhaustVelocity += engine.thrustVec * (float)((engine.isp * BasicDeltaV.GRAVITY) / engine.actualThrust);
                totalActualExhaustVelocity         += totalActualVectoredExhaustVelocity.magnitude;

                totalStageFlowRate    += engine.ResourceConsumptions.Mass;
                totalStageIspFlowRate += engine.ResourceConsumptions.Mass * engine.isp;

                for (int j = 0; j < engine.appliedForces.Count; ++j)
                {
                    totalStageThrustForce.AddForce(engine.appliedForces[j]);
                }
            }
            if (log != null)
            {
                log.AppendLine("vecThrust = ", vecThrust.ToString(), "   magnitude = ", vecThrust.magnitude);
            }
            totalStageThrust       = vecThrust.magnitude;
            totalStageActualThrust = vecActualThrust.magnitude;

            // Calculate the effective isp at this point
            if (totalStageFlowRate > 0d && totalStageIspFlowRate > 0d)
            {
                currentisp = totalStageIspFlowRate / totalStageFlowRate;
            }
            else
            {
                currentisp = 0;
            }
        }
Example #3
0
        // This function activates the next stage
        // currentStage must be updated before calling this function
        private void ActivateStage()
        {
            // Build a set of all the parts that will be decoupled
            decoupledParts.Clear();
            for (int i = 0; i < allParts.Count; ++i)
            {
                PartSim partSim = allParts[i];

                if (partSim.decoupledInStage >= currentStage)
                {
                    decoupledParts.Add(partSim);
                }
            }

            foreach (PartSim partSim in decoupledParts)
            {
                // Remove it from the all parts list
                allParts.Remove(partSim);
                partSim.Release();
                if (partSim.isEngine)
                {
                    // If it is an engine then loop through all the engine modules and remove all the ones from this engine part
                    for (int i = allEngines.Count - 1; i >= 0; i--)
                    {
                        EngineSim engine = allEngines[i];
                        if (engine.partSim == partSim)
                        {
                            allEngines.RemoveAt(i);
                            engine.Release();
                        }
                    }
                }
                // If it is a fuel line then remove it from the list of all fuel lines
                if (partSim.isFuelLine)
                {
                    allFuelLines.Remove(partSim);
                }
            }

            // Loop through all the (remaining) parts
            for (int i = 0; i < allParts.Count; ++i)
            {
                // Ask the part to remove all the parts that are decoupled
                allParts[i].RemoveAttachedParts(decoupledParts);
            }

            // Now we loop through all the engines and activate those that are ignited in this stage
            for (int i = 0; i < allEngines.Count; ++i)
            {
                EngineSim engine = allEngines[i];
                if (engine.partSim.inverseStage == currentStage)
                {
                    engine.isActive = true;
                }
            }
        }
Example #4
0
 private void UpdateStageEngines()
 {
     stageEngines.Clear();
     for (int i = 0; i < allEngines.Count; i++)
     {
         EngineSim engine = allEngines[i];
         if (engine.partSim.inverseStage >= currentStage)
         {
             stageEngines.Add(engine);
         }
     }
 }
Example #5
0
 // This function simply rebuilds the active engines by testing the isActive flag of all the engines
 private void UpdateActiveEngines()
 {
     activeEngines.Clear();
     for (int i = 0; i < allEngines.Count; ++i)
     {
         EngineSim engine = allEngines[i];
         if (engine.isActive && engine.isFlamedOut == false)
         {
             activeEngines.Add(engine);
         }
     }
 }
Example #6
0
        // This function does all the hard work of working out which engines are burning, which tanks are being drained
        // and setting the drain rates
        private void UpdateResourceDrains()
        {
            // Update the active engines
            UpdateActiveEngines();

            // Empty the draining resources set
            drainingResources.Clear();

            // Reset the resource drains of all draining parts
            foreach (PartSim partSim in drainingParts)
            {
                partSim.resourceDrains.Reset();
            }

            // Empty the draining parts set
            drainingParts.Clear();

            // Loop through all the active engine modules
            for (int i = 0; i < activeEngines.Count; ++i)
            {
                EngineSim engine = activeEngines[i];

                // Set the resource drains for this engine
                if (engine.SetResourceDrains(log, allParts, allFuelLines, drainingParts))
                {
                    // If it is active then add the consumed resource types to the set
                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; ++j)
                    {
                        drainingResources.Add(engine.ResourceConsumptions.Types[j]);
                    }
                }
            }

            // Update the active engines again to remove any engines that have no fuel supply
            UpdateActiveEngines();

            if (log != null)
            {
                log.AppendLine("Active engines = ", activeEngines.Count);
                int i = 0;
                for (int j = 0; j < activeEngines.Count; j++)
                {
                    EngineSim engine = activeEngines[j];
                    log.Append("Engine " + (i++) + ":");
                    engine.DumpEngineToLog(log);
                }
                log.Flush();
            }
        }
Example #7
0
 private static void Reset(EngineSim engineSim)
 {
     engineSim.resourceConsumptions.Reset();
     engineSim.maxResourceConsumptions.Reset();
     engineSim.resourceFlowModes.Reset();
     engineSim.partSim      = null;
     engineSim.actualThrust = 0;
     engineSim.isActive     = false;
     engineSim.isp          = 0;
     for (int i = 0; i < engineSim.appliedForces.Count; i++)
     {
         engineSim.appliedForces[i].Release();
     }
     engineSim.appliedForces.Clear();
     engineSim.thrust      = 0;
     engineSim.fullThrust  = 0;
     engineSim.maxMach     = 0f;
     engineSim.isFlamedOut = false;
 }
Example #8
0
        private void UpdateStageResourceSources()
        {
            UpdateStageEngines();

            maxResourceParts.Clear();

            maxResources.Clear();

            for (int i = 0; i < stageEngines.Count; i++)
            {
                EngineSim engine = stageEngines[i];

                if (engine.SetPossibleResourceDrains(log, allParts, maxResourceParts))
                {
                    for (int j = 0; j < engine.ResourceConsumptions.Types.Count; j++)
                    {
                        maxResources.Add(engine.ResourceConsumptions.Types[j]);
                    }
                }
            }
        }
Example #9
0
        public void CreateEngineSims(List <EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
        {
            if (log != null)
            {
                log.AppendLine("CreateEngineSims for ", this.name);
            }
            List <ModuleEngines> cacheModuleEngines = part.FindModulesImplementing <ModuleEngines>();

            try
            {
                if (cacheModuleEngines.Count > 0)
                {
                    //find first active engine, assuming that two are never active at the same time
                    foreach (ModuleEngines engine in cacheModuleEngines)
                    {
                        if (engine.isEnabled)
                        {
                            if (log != null)
                            {
                                log.AppendLine("Module: ", engine.moduleName);
                            }
                            EngineSim engineSim = EngineSim.New(
                                this,
                                engine,
                                atmosphere,
                                (float)mach,
                                vectoredThrust,
                                fullThrust,
                                log);
                            allEngines.Add(engineSim);
                        }
                    }
                }
            }
            catch
            {
                Debug.Log("[KER] Error Catch in CreateEngineSims");
            }
        }
Example #10
0
        public static EngineSim New(PartSim theEngine,
                                    ModuleEngines engineMod,
                                    double atmosphere,
                                    float machNumber,
                                    bool vectoredThrust,
                                    bool fullThrust,
                                    LogMsg log)
        {
            float            maxFuelFlow                = engineMod.maxFuelFlow;
            float            minFuelFlow                = engineMod.minFuelFlow;
            float            thrustPercentage           = engineMod.thrustPercentage;
            List <Transform> thrustTransforms           = engineMod.thrustTransforms;
            List <float>     thrustTransformMultipliers = engineMod.thrustTransformMultipliers;
            Vector3          vecThrust = CalculateThrustVector(vectoredThrust ? thrustTransforms : null,
                                                               vectoredThrust ? thrustTransformMultipliers : null,
                                                               log);
            FloatCurve        atmosphereCurve = engineMod.atmosphereCurve;
            bool              atmChangeFlow   = engineMod.atmChangeFlow;
            FloatCurve        atmCurve        = engineMod.useAtmCurve ? engineMod.atmCurve : null;
            FloatCurve        velCurve        = engineMod.useVelCurve ? engineMod.velCurve : null;
            float             currentThrottle = engineMod.currentThrottle;
            float             IspG            = engineMod.g;
            bool              throttleLocked  = engineMod.throttleLocked || fullThrust;
            List <Propellant> propellants     = engineMod.propellants;
            bool              active          = engineMod.isOperational;
            float             resultingThrust = engineMod.resultingThrust;
            bool              isFlamedOut     = engineMod.flameout;

            EngineSim engineSim = pool.Borrow();

            engineSim.isp          = 0.0;
            engineSim.maxMach      = 0.0f;
            engineSim.actualThrust = 0.0;
            engineSim.partSim      = theEngine;
            engineSim.isActive     = active;
            engineSim.thrustVec    = vecThrust;
            engineSim.isFlamedOut  = isFlamedOut;
            engineSim.resourceConsumptions.Reset();
            engineSim.maxResourceConsumptions.Reset();
            engineSim.resourceFlowModes.Reset();
            engineSim.appliedForces.Clear();

            double flowRate    = 0.0;
            double maxFlowRate = 0.0;

            if (engineSim.partSim.hasVessel)
            {
                if (log != null)
                {
                    log.AppendLine("hasVessel is true");
                }

                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach);
                engineSim.isp          = atmosphereCurve.Evaluate((float)atmosphere);
                engineSim.fullThrust   = GetThrust(maxFuelFlow * flowModifier, engineSim.isp);
                engineSim.thrust       = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
                engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0;
                if (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                }

                if (throttleLocked)
                {
                    if (log != null)
                    {
                        log.AppendLine("throttleLocked is true, using thrust for flowRate");
                    }
                    flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                }
                else
                {
                    if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                    {
                        // TODO: This bit doesn't work for RF engines
                        if (log != null)
                        {
                            log.AppendLine("throttled up and not landed, using actualThrust for flowRate");
                        }
                        flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                    }
                    else
                    {
                        if (log != null)
                        {
                            log.AppendLine("throttled down or landed, using thrust for flowRate");
                        }
                        flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                    }
                }

                maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp);
            }
            else
            {
                if (log != null)
                {
                    log.buf.AppendLine("hasVessel is false");
                }
                float altitude     = BasicDeltaV.Instance.AtmosphereDepth;
                float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, BasicDeltaV.Instance.CurrentCelestialBody.GetDensity(BasicDeltaV.Instance.CurrentCelestialBody.GetPressure(altitude), BasicDeltaV.Instance.CurrentCelestialBody.GetTemperature(altitude)), velCurve, machNumber, ref engineSim.maxMach);
                engineSim.isp          = atmosphereCurve.Evaluate((float)atmosphere);
                engineSim.fullThrust   = GetThrust(maxFuelFlow * flowModifier, engineSim.isp);
                engineSim.thrust       = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
                engineSim.actualThrust = 0d;
                if (log != null)
                {
                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
                    log.AppendLine("no vessel, using thrust for flowRate");
                }

                flowRate    = GetFlowRate(engineSim.thrust, engineSim.isp);
                maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp);
            }

            if (log != null)
            {
                log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate);
            }

            float flowMass = 0f;

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];
                if (!propellant.ignoreForIsp)
                {
                    flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
                }
            }

            if (log != null)
            {
                log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);
            }

            for (int i = 0; i < propellants.Count; ++i)
            {
                Propellant propellant = propellants[i];

                if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir")
                {
                    continue;
                }

                double consumptionRate = propellant.ratio * flowRate / flowMass;

                if (log != null)
                {
                    log.buf.AppendFormat(
                        "Add consumption({0}, {1}:{2:d}) = {3:g6}\n",
                        ResourceContainer.GetResourceName(propellant.id),
                        theEngine.name,
                        theEngine.partId,
                        consumptionRate);
                }

                engineSim.resourceConsumptions.Add(propellant.id, consumptionRate);
                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());

                double maxConsumptionRate = propellant.ratio * maxFlowRate / flowMass;

                engineSim.maxResourceConsumptions.Add(propellant.id, maxConsumptionRate);
            }

            for (int i = 0; i < thrustTransforms.Count; i++)
            {
                Transform thrustTransform = thrustTransforms[i];
                Vector3d  direction       = thrustTransform.forward.normalized;
                Vector3d  position        = thrustTransform.position;

                AppliedForce appliedForce = AppliedForce.New(direction * engineSim.thrust * thrustTransformMultipliers[i], position);
                engineSim.appliedForces.Add(appliedForce);
            }

            return(engineSim);
        }
Example #11
0
        // This function runs the simulation and returns a newly created array of Stage objects
        public Stage[] RunSimulation(LogMsg _log)
        {
            log = _log;
            if (log != null)
            {
                log.AppendLine("RunSimulation started");
            }

            _timer.Reset();
            _timer.Start();

            // Start with the last stage to simulate
            // (this is in a member variable so it can be accessed by AllowedToStage and ActivateStage)
            currentStage = lastStage;
            // Work out which engines would be active if just doing the staging and if this is different to the
            // currently active engines then generate an extra stage
            // Loop through all the engines
            bool anyActive = false;

            for (int i = 0; i < allEngines.Count; ++i)
            {
                EngineSim engine = allEngines[i];

                if (log != null)
                {
                    log.AppendLine("Testing engine mod of ", engine.partSim.name, ":", engine.partSim.partId);
                }

                bool bActive = engine.isActive;
                bool bStage  = (engine.partSim.inverseStage >= currentStage);
                if (log != null)
                {
                    log.AppendLine("bActive = ", bActive, "   bStage = ", bStage);
                }
                if (HighLogic.LoadedSceneIsFlight)
                {
                    if (bActive)
                    {
                        anyActive = true;
                    }
                    if (bActive != bStage)
                    {
                        // If the active state is different to the state due to staging
                        if (log != null)
                        {
                            log.AppendLine("Need to do current active engines first");
                        }
                        doingCurrent = true;
                    }
                }
                else
                {
                    if (bStage)
                    {
                        if (log != null)
                        {
                            log.AppendLine("Marking as active");
                        }
                        engine.isActive = true;
                    }
                }
            }

            // If we need to do current because of difference in engine activation and there actually are active engines
            // then we do the extra stage otherwise activate the next stage and don't treat it as current
            if (doingCurrent && anyActive)
            {
                currentStage++;
            }
            else
            {
                ActivateStage();
                doingCurrent = false;
            }

            // Create a list of lists of PartSims that prevent decoupling
            BuildDontStageLists(log);

            if (log != null)
            {
                log.Flush();
            }

            // Create the array of stages that will be returned
            Stage[] stages = new Stage[currentStage + 1];

            int startStage = currentStage;

            // Loop through the stages
            while (currentStage >= 0)
            {
                if (log != null)
                {
                    log.AppendLine("Simulating stage ", currentStage);
                    log.Flush();
                    _timer.Reset();
                    _timer.Start();
                }

                // Update active engines and resource drains
                UpdateResourceDrains();

                UpdateStageResourceSources();

                // Update the masses of the parts to correctly handle "no physics" parts
                stageStartMass = UpdatePartMasses();

                stageFullMass = UpdateFullResourceMass();

                if (log != null)
                {
                    allParts[0].DumpPartToLog(log, "", allParts);
                }

                // Create the Stage object for this stage
                Stage stage = new Stage();

                stageTime      = 0d;
                vecStageDeltaV = Vector3.zero;

                stageStartCom = ShipCom;

                stepStartMass = stageStartMass;
                stepEndMass   = 0;

                CalculateThrustAndISP();

                CalculateFullThrustAndISP();

                stage.startMass     = stageStartMass;
                stage.stageFullMass = stageFullMass;

                // Store various things in the Stage object
                stage.simpleThrust                       = simpleTotalThrust;
                stage.actualSimpleThrust                 = simpleActualTotalThrust;
                stage.thrust                             = totalStageThrust;
                stage.thrustToWeight                     = totalStageThrust / (stageStartMass * gravity);
                stage.maxThrustToWeight                  = stage.thrustToWeight;
                stage.actualThrust                       = totalStageActualThrust;
                stage.actualThrustToWeight               = totalStageActualThrust / (stageStartMass * gravity);
                stage.thrustVector                       = vecThrust;
                stage.actualThrustVector                 = vecActualThrust;
                stage.totalExhaustVelocity               = totalExhaustVelocity;
                stage.totalActualExhaustVelocity         = totalActualExhaustVelocity;
                stage.totalVectoredExhaustVelocity       = totalVectoredExhaustVelocity;
                stage.totalVectoredActualExhaustVelocity = totalActualVectoredExhaustVelocity;
                if (log != null)
                {
                    log.AppendLine("stage.thrust = ", stage.thrust);
                    log.AppendLine("StageMass = ", stageStartMass);
                    log.AppendLine("Initial maxTWR = ", stage.maxThrustToWeight);
                }

                // calculate torque and associates
                stage.maxThrustTorque = totalStageThrustForce.TorqueAt(stageStartCom).magnitude;

                // torque divided by thrust. imagine that all engines are at the end of a lever that tries to turn the ship.
                // this numerical value, in meters, would represent the length of that lever.
                double torqueLeverArmLength = (stage.thrust <= 0) ? 0 : stage.maxThrustTorque / stage.thrust;

                // how far away are the engines from the CoM, actually?
                double thrustDistance = (stageStartCom - totalStageThrustForce.GetAverageForceApplicationPoint()).magnitude;

                // the combination of the above two values gives an approximation of the offset angle.
                double sinThrustOffsetAngle = 0;
                if (thrustDistance > 1e-7)
                {
                    sinThrustOffsetAngle = torqueLeverArmLength / thrustDistance;
                    if (sinThrustOffsetAngle > 1)
                    {
                        sinThrustOffsetAngle = 1;
                    }
                }

                stage.thrustOffsetAngle = Math.Asin(sinThrustOffsetAngle) * 180 / Math.PI;

                // Calculate the total cost of the vessel at this point
                stage.totalCost = 0d;
                for (int i = 0; i < allParts.Count; ++i)
                {
                    if (currentStage > allParts[i].decoupledInStage)
                    {
                        stage.totalCost += allParts[i].GetCost(currentStage);
                    }
                }

                // The total mass is simply the mass at the start of the stage
                stage.totalMass = stageStartMass;

                // If we have done a previous stage
                if (currentStage < startStage)
                {
                    // Calculate what the previous stage's mass and cost were by subtraction
                    Stage prev = stages[currentStage + 1];
                    prev.cost = prev.totalCost - stage.totalCost;
                    prev.mass = prev.totalMass - stage.totalMass;
                }

                // The above code will never run for the last stage so set those directly
                if (currentStage == 0)
                {
                    stage.cost = stage.totalCost;
                    stage.mass = stage.totalMass;
                }

                dontStageParts = dontStagePartsLists[currentStage];

                if (log != null)
                {
                    log.AppendLine("Stage setup took ", _timer.ElapsedMilliseconds, "ms");

                    if (dontStageParts.Count > 0)
                    {
                        log.AppendLine("Parts preventing staging:");
                        for (int i = 0; i < dontStageParts.Count; i++)
                        {
                            PartSim partSim = dontStageParts[i];
                            partSim.DumpPartToLog(log, "");
                        }
                    }
                    else
                    {
                        log.AppendLine("No parts preventing staging");
                    }

                    log.Flush();
                }


                // Now we will loop until we are allowed to stage
                int loopCounter = 0;
                while (!AllowedToStage())
                {
                    loopCounter++;
                    //if (log != null) log.AppendLine("loop = ", loopCounter);
                    // Calculate how long each draining tank will take to drain and run for the minimum time
                    double  resourceDrainTime = double.MaxValue;
                    PartSim partMinDrain      = null;
                    foreach (PartSim partSim in drainingParts)
                    {
                        double time = partSim.TimeToDrainResource(log);
                        if (time < resourceDrainTime)
                        {
                            resourceDrainTime = time;
                            partMinDrain      = partSim;
                        }
                    }

                    if (log != null)
                    {
                        log.Append("Drain time = ", resourceDrainTime, " (", partMinDrain.name)
                        .AppendLine(":", partMinDrain.partId, ")");
                    }
                    foreach (PartSim partSim in drainingParts)
                    {
                        partSim.DrainResources(resourceDrainTime, log);
                    }

                    // Get the mass after draining
                    stepEndMass = ShipMass;
                    stageTime  += resourceDrainTime;

                    stage.endMass = stepEndMass;

                    double stepEndTWR = totalStageThrust / (stepEndMass * gravity);

                    /*if (log != null)
                     * {
                     *      log.AppendLine("After drain mass = ", stepEndMass);
                     *      log.AppendLine("currentThrust = ", totalStageThrust);
                     *      log.AppendLine("currentTWR = ", stepEndTWR);
                     * }*/
                    if (stepEndTWR > stage.maxThrustToWeight)
                    {
                        stage.maxThrustToWeight = stepEndTWR;
                    }

                    //if (log != null) log.AppendLine("newMaxTWR = ", stage.maxThrustToWeight);

                    // If we have drained anything and the masses make sense then add this step's deltaV to the stage total
                    if (resourceDrainTime > 0d && stepStartMass > stepEndMass && stepStartMass > 0d && stepEndMass > 0d)
                    {
                        vecStageDeltaV += vecThrust * (float)((currentisp * GRAVITY * Math.Log(stepStartMass / stepEndMass)) / simpleTotalThrust);
                    }

                    // Update the active engines and resource drains for the next step
                    UpdateResourceDrains();

                    // Recalculate the current thrust and isp for the next step
                    CalculateThrustAndISP();

                    // Check if we actually changed anything
                    if (stepStartMass == stepEndMass)
                    {
                        //MonoBehaviour.print("No change in mass");
                        break;
                    }

                    // Check to stop rampant looping
                    if (loopCounter == 1000)
                    {
                        if (log != null)
                        {
                            log.AppendLine("exceeded loop count");
                            log.AppendLine("stageStartMass = " + stageStartMass);
                            log.AppendLine("stepStartMass = " + stepStartMass);
                            log.AppendLine("StepEndMass   = " + stepEndMass);
                        }
                        break;
                    }

                    // The next step starts at the mass this one ended at
                    stepStartMass = stepEndMass;
                }

                if (stage.stageFullMass > stage.endMass && stage.stageFullMass > 0d && stage.endMass > 0d)
                {
                    stage.stageStartDeltaV = (fullVecThrust * (float)((fullISP * GRAVITY * Math.Log(stage.stageFullMass / stage.endMass)) / fullSimpleThrust)).magnitude;
                }

                // Store more values in the Stage object and stick it in the array

                // Store the magnitude of the deltaV vector
                stage.deltaV       = vecStageDeltaV.magnitude;
                stage.resourceMass = stageStartMass - stepEndMass;

                // Recalculate effective stage isp from the stage deltaV (flip the standard deltaV calculation around)
                // Note: If the mass doesn't change then this is a divide by zero
                if (stageStartMass != stepStartMass)
                {
                    stage.isp = stage.deltaV / (GRAVITY * Math.Log(stageStartMass / stepStartMass));
                }
                else
                {
                    stage.isp = 0;
                }

                // Zero stage time if more than a day (this should be moved into the window code)
                stage.time           = (stageTime < SECONDS_PER_DAY) ? stageTime : 0d;
                stage.number         = doingCurrent ? -1 : currentStage;         // Set the stage number to -1 if doing current engines
                stage.totalPartCount = allParts.Count;
                stage.maxMach        = maxMach;
                stages[currentStage] = stage;

                // Now activate the next stage
                currentStage--;
                doingCurrent = false;

                if (log != null)
                {
                    // Log how long the stage took
                    _timer.Stop();
                    log.AppendLine("Simulating stage took ", _timer.ElapsedMilliseconds, "ms");
                    stage.Dump(log);
                    _timer.Reset();
                    _timer.Start();
                }

                // Activate the next stage
                ActivateStage();

                if (log != null)
                {
                    // Log how long it took to activate
                    _timer.Stop();
                    log.AppendLine("ActivateStage took ", _timer.ElapsedMilliseconds, "ms");
                }
            }

            // Now we add up the various total fields in the stages
            for (int i = 0; i < stages.Length; i++)
            {
                // For each stage we total up the cost, mass, deltaV and time for this stage and all the stages above
                for (int j = i; j >= 0; j--)
                {
                    stages[i].totalStartDeltaV += stages[j].stageStartDeltaV;
                    stages[i].totalDeltaV      += stages[j].deltaV;
                    stages[i].totalTime        += stages[j].time;
                    stages[i].partCount         = i > 0 ? stages[i].totalPartCount - stages[i - 1].totalPartCount : stages[i].totalPartCount;
                }
                // We also total up the deltaV for stage and all stages below
                for (int j = i; j < stages.Length; j++)
                {
                    stages[i].inverseTotalDeltaV += stages[j].deltaV;
                }

                // Zero the total time if the value will be huge (24 hours?) to avoid the display going weird
                // (this should be moved into the window code)
                if (stages[i].totalTime > SECONDS_PER_DAY)
                {
                    stages[i].totalTime = 0d;
                }
            }

            FreePooledObject();

            _timer.Stop();

            if (log != null)
            {
                log.AppendLine("RunSimulation: ", _timer.ElapsedMilliseconds, "ms");
                log.Flush();
            }
            log = null;

            return(stages);
        }
Example #12
0
        // This function works out if it is time to stage
        private bool AllowedToStage()
        {
            if (log != null)
            {
                log.AppendLine("AllowedToStage")
                .AppendLine("currentStage = ", currentStage);
            }

            if (activeEngines.Count > 0)
            {
                for (int i = 0; i < dontStageParts.Count; ++i)
                {
                    PartSim partSim = dontStageParts[i];

                    if (log != null)
                    {
                        partSim.DumpPartToLog(log, "Testing: ");
                    }
                    //if (log != null) log.AppendLine("isSepratron = ", partSim.isSepratron ? "true" : "false");

                    if (!partSim.isSepratron && !partSim.EmptyOf(drainingResources))
                    {
                        if (log != null)
                        {
                            partSim.DumpPartToLog(log, "Decoupled part not empty => false: ");
                        }
                        return(false);
                    }

                    if (partSim.isEngine)
                    {
                        for (int j = 0; j < activeEngines.Count; ++j)
                        {
                            EngineSim engine = activeEngines[j];

                            if (engine.dontDecoupleActive && engine.partSim == partSim)
                            {
                                if (log != null)
                                {
                                    partSim.DumpPartToLog(log, "Decoupled part is active engine => false: ");
                                }
                                return(false);
                            }
                        }
                    }
                }
            }

            if (currentStage == 0 && doingCurrent)
            {
                if (log != null)
                {
                    log.AppendLine("Current stage == 0 && doingCurrent => false");
                }
                return(false);
            }

            if (log != null)
            {
                log.AppendLine("Returning true");
            }
            return(true);
        }