Beispiel #1
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.ResourceConsumptionsForMass.Types.Count; ++j)
                    {
                        drainingResources.Add(engine.ResourceConsumptionsForMass.Types[j]);
                    }
                }
            }

            //foreach (RCSSim r in allRCS) {
            //    r.SetResourceDrains(log, allParts);
            //}



            // 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();
            }
        }
Beispiel #2
0
        public void Dump(LogMsg log)
        {
            log.buf.AppendFormat("number        : {0:d}\n", this.number);
            log.buf.AppendFormat("cost          : {0:g6}\n", this.cost);
            log.buf.AppendFormat("totalCost     : {0:g6}\n", this.totalCost);
            log.buf.AppendFormat("time          : {0:g6}\n", this.time);
            log.buf.AppendFormat("totalTime     : {0:g6}\n", this.totalTime);
            log.buf.AppendFormat("mass          : {0:g6}\n", this.mass);
            log.buf.AppendFormat("fullMass      : {0:g6}\n", this.stageFullMass);
            log.buf.AppendFormat("resourceMass  : {0:g6}\n", this.resourceMass);
            log.buf.AppendFormat("endMass       : {0:g6}\n", this.endMass);
            log.buf.AppendFormat("totalMass     : {0:g6}\n", this.totalMass);
            log.buf.AppendFormat("isp           : {0:g6}\n", this.isp);
            log.buf.AppendFormat("thrust        : {0:g6}\n", this.thrust);
            log.buf.AppendFormat("actualThrust  : {0:g6}\n", this.actualThrust);
            log.buf.AppendFormat("simpleThrust  : {0:g6}\n", this.simpleThrust);
            log.buf.AppendFormat("thrustToWeight: {0:g6}\n", this.thrustToWeight);
            log.buf.AppendFormat("maxTWR        : {0:g6}\n", this.maxThrustToWeight);
            log.buf.AppendFormat("actualTWR     : {0:g6}\n", this.actualThrustToWeight);
            log.buf.AppendFormat("ThrustTorque  : {0:g6}\n", this.maxThrustTorque);
            log.buf.AppendFormat("ThrustOffset  : {0:g6}\n", this.thrustOffsetAngle);
            log.buf.AppendFormat("deltaV        : {0:g6}\n", this.deltaV);
            log.buf.AppendFormat("totalDeltaV   : {0:g6}\n", this.totalDeltaV);
            log.buf.AppendFormat("invTotDeltaV  : {0:g6}\n", this.inverseTotalDeltaV);
            log.buf.AppendFormat("stageDeltaV   : {0:g6}\n", this.stageStartDeltaV);

            log.Flush();
        }
Beispiel #3
0
 public void Dump(LogMsg log)
 {
     log.buf.AppendFormat("number        : {0:d}\n", this.number);
     log.buf.AppendFormat("cost          : {0:g6}\n", this.cost);
     log.buf.AppendFormat("totalCost     : {0:g6}\n", this.totalCost);
     log.buf.AppendFormat("time          : {0:g6}\n", this.time);
     log.buf.AppendFormat("totalTime     : {0:g6}\n", this.totalTime);
     log.buf.AppendFormat("mass          : {0:g6}\n", this.mass);
     log.buf.AppendFormat("totalMass     : {0:g6}\n", this.totalMass);
     log.buf.AppendFormat("isp           : {0:g6}\n", this.isp);
     log.buf.AppendFormat("thrust        : {0:g6}\n", this.thrust);
     log.buf.AppendFormat("actualThrust  : {0:g6}\n", this.actualThrust);
     log.buf.AppendFormat("thrustToWeight: {0:g6}\n", this.thrustToWeight);
     log.buf.AppendFormat("maxTWR        : {0:g6}\n", this.maxThrustToWeight);
     log.buf.AppendFormat("actualTWR     : {0:g6}\n", this.actualThrustToWeight);
     log.buf.AppendFormat("ThrustTorque  : {0:g6}\n", this.maxThrustTorque);
     log.buf.AppendFormat("ThrustOffset  : {0:g6}\n", this.thrustOffsetAngle);
     log.buf.AppendFormat("deltaV        : {0:g6}\n", this.deltaV);
     log.buf.AppendFormat("totalDeltaV   : {0:g6}\n", this.totalDeltaV);
     log.buf.AppendFormat("invTotDeltaV  : {0:g6}\n", this.inverseTotalDeltaV);
     log.buf.AppendFormat("RCSdeltaVStart        : {0:g6}\n", this.RCSdeltaVStart);
     log.buf.AppendFormat("RCSIsp   : {0:g6}\n", this.RCSIsp);
     log.buf.AppendFormat("RCSThrust  : {0:g6}\n", this.RCSThrust);
     log.buf.AppendFormat("RCSTWRStart        : {0:g6}\n", this.RCSTWRStart);
     log.buf.AppendFormat("RCSdeltaVEnd   : {0:g6}\n", this.RCSdeltaVEnd);
     log.buf.AppendFormat("RCSTWREnd  : {0:g6}\n", this.RCSTWREnd);
     log.Flush();
 }
        private static void CheckForMods()
        {
            hasCheckedForMods = true;

            foreach (var assembly in AssemblyLoader.loadedAssemblies)
            {
                log.AppendLine("Assembly: ", assembly.assembly);

                var name = assembly.assembly.ToString().Split(',')[0];

                if (name == "RealFuels")
                {
                    log.AppendLine("Found RealFuels mod");

                    var RF_ModuleEngineConfigs_Type = assembly.assembly.GetType("RealFuels.ModuleEngineConfigs");
                    if (RF_ModuleEngineConfigs_Type != null)
                    {
                        RF_ModuleEngineConfigs_localCorrectThrust = RF_ModuleEngineConfigs_Type.GetField("localCorrectThrust");
                    }

                    var RF_ModuleHybridEngine_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngine");
                    if (RF_ModuleHybridEngine_Type != null)
                    {
                        RF_ModuleHybridEngine_localCorrectThrust = RF_ModuleHybridEngine_Type.GetField("localCorrectThrust");
                    }

                    var RF_ModuleHybridEngines_Type = assembly.assembly.GetType("RealFuels.ModuleHybridEngines");
                    if (RF_ModuleHybridEngines_Type != null)
                    {
                        RF_ModuleHybridEngines_localCorrectThrust = RF_ModuleHybridEngines_Type.GetField("localCorrectThrust");
                    }

                    hasInstalledRealFuels = true;
                    break;
                }
                else if (name == "KerbalIspDifficultyScaler")
                {
                    log.AppendLine("Found KIDS mod");

                    var KIDS_Utils_Type = assembly.assembly.GetType("KerbalIspDifficultyScaler.KerbalIspDifficultyScalerUtils");
                    if (KIDS_Utils_Type != null)
                    {
                        KIDS_Utils_GetIspMultiplier = KIDS_Utils_Type.GetMethod("GetIspMultiplier");
                    }

                    KIDSparameters   = new object[6];
                    hasInstalledKIDS = true;
                }
            }
            log.Flush();
        }
Beispiel #5
0
        public void Dump(LogMsg log)
        {
            log.buf.AppendFormat("number        : {0:d}\n", this.number);
            log.buf.AppendFormat("cost          : {0:g6}\n", this.cost);
            log.buf.AppendFormat("totalCost     : {0:g6}\n", this.totalCost);
            log.buf.AppendFormat("time          : {0:g6}\n", this.time);
            log.buf.AppendFormat("totalTime     : {0:g6}\n", this.totalTime);
            log.buf.AppendFormat("mass          : {0:g6}\n", this.mass);
            log.buf.AppendFormat("totalMass     : {0:g6}\n", this.totalMass);
            log.buf.AppendFormat("isp           : {0:g6}\n", this.isp);
            log.buf.AppendFormat("thrust        : {0:g6}\n", this.thrust);
            log.buf.AppendFormat("actualThrust  : {0:g6}\n", this.actualThrust);
            log.buf.AppendFormat("thrustToWeight: {0:g6}\n", this.thrustToWeight);
            log.buf.AppendFormat("maxTWR        : {0:g6}\n", this.maxThrustToWeight);
            log.buf.AppendFormat("actualTWR     : {0:g6}\n", this.actualThrustToWeight);
            log.buf.AppendFormat("ThrustTorque  : {0:g6}\n", this.maxThrustTorque);
            log.buf.AppendFormat("ThrustOffset  : {0:g6}\n", this.thrustOffsetAngle);
            log.buf.AppendFormat("deltaV        : {0:g6}\n", this.deltaV);
            log.buf.AppendFormat("totalDeltaV   : {0:g6}\n", this.totalDeltaV);
            log.buf.AppendFormat("invTotDeltaV  : {0:g6}\n", this.inverseTotalDeltaV);

            log.Flush();
        }
Beispiel #6
0
        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
        {
            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + this.name);
                for (int i = 0; i < this.part.Modules.Count; i++)
                {
                    PartModule partMod = this.part.Modules[i];
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }
            }

            if (hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEngines but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEngines that is active
                string mode = part.GetModule<MultiModeEngine>().mode;

                List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
                for (int i = 0; i < engines.Count; ++i)
                {
                    ModuleEngines engine = engines[i];
                    if (engine.engineID == mode)
                    {
                        if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);

                        EngineSim engineSim = EngineSim.New(
                            this,
                            engine,
                            atmosphere,
                            (float)mach,
                            vectoredThrust,
                            fullThrust,
                            log);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else if (hasModuleEngines)
            {
                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);

                    EngineSim engineSim = EngineSim.New(
                        this,
                        engine,
                        atmosphere,
                        (float)mach,
                        vectoredThrust,
                        fullThrust,
                        log);
                    allEngines.Add(engineSim);
                }
            }

            if (log != null)
            {
                log.Flush();
            }
        }
Beispiel #7
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();

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

                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();


                // Store various things in the Stage object
                stage.thrust               = totalStageThrust;
                stage.thrustToWeight       = totalStageThrust / (stageStartMass * gravity);
                stage.maxThrustToWeight    = stage.thrustToWeight;
                stage.actualThrust         = totalStageActualThrust;
                stage.actualThrustToWeight = totalStageActualThrust / (stageStartMass * gravity);

                CalculateRCS(gravity, false);

                stage.RCSIsp         = RCSIsp;
                stage.RCSThrust      = RCSThrust;
                stage.RCSdeltaVStart = RCSDeltaV;
                stage.RCSTWRStart    = RCSTWR;
                stage.RCSBurnTime    = RCSBurnTime;

                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;

                    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 * Units.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;
                }

                // 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;

                if (HighLogic.LoadedSceneIsEditor) //this is only needed in the VAB.
                {
                    CalculateRCS(gravity, true);
                }

                stage.RCSdeltaVEnd = RCSDeltaV;
                stage.RCSTWREnd    = RCSTWR;

                // 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 / (Units.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].totalDeltaV       += stages[j].deltaV;
                    stages[i].totalResourceMass += stages[j].resourceMass;
                    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);
        }
Beispiel #8
0
        // This function prepares the simulation by creating all the necessary data structures it will
        // need during the simulation.  All required data is copied from the core game data structures
        // so that the simulation itself can be run in a background thread without having issues with
        // the core game changing the data while the simulation is running.
        public bool PrepareSimulation(LogMsg _log, List <Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false)
        {
            log = _log;
            if (log != null)
            {
                log.AppendLine("PrepareSimulation started");
            }

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

            // Store the parameters in members for ease of access in other functions
            partList   = parts;
            gravity    = theGravity;
            atmosphere = theAtmosphere;
            mach       = theMach;
            lastStage  = StageManager.LastStage;
            maxMach    = 1.0f;
            if (log != null)
            {
                log.AppendLine("lastStage = ", lastStage);
            }

            // Clear the lists for our simulation parts
            allParts.Clear();
            allFuelLines.Clear();
            drainingParts.Clear();
            allEngines.Clear();
            activeEngines.Clear();
            drainingResources.Clear();

            // A dictionary for fast lookup of Part->PartSim during the preparation phase
            partSimLookup.Clear();

            if (partList.Count > 0 && partList[0].vessel != null)
            {
                vesselName = partList[0].vessel.vesselName;
                vesselType = partList[0].vessel.vesselType;
            }
            // First we create a PartSim for each Part (giving each a unique id)
            int partId = 1;

            for (int i = 0; i < partList.Count; ++i)
            {
                Part part = partList[i];

                // If the part is already in the lookup dictionary then log it and skip to the next part
                if (partSimLookup.ContainsKey(part))
                {
                    if (log != null)
                    {
                        log.AppendLine("Part ", part.name, " appears in vessel list more than once");
                    }
                    continue;
                }

                // Create the PartSim
                PartSim partSim = PartSim.New(part, partId, atmosphere, log);

                // Add it to the Part lookup dictionary and the necessary lists
                partSimLookup.Add(part, partSim);
                allParts.Add(partSim);

                if (partSim.isFuelLine)
                {
                    allFuelLines.Add(partSim);
                }

                if (partSim.isEngine)
                {
                    partSim.CreateEngineSims(allEngines, atmosphere, mach, vectoredThrust, fullThrust, log);
                }

                if (partSim.isRCS)
                {
                    partSim.CreateRCSSims(allRCS, atmosphere, mach, vectoredThrust, fullThrust, log);
                }

                partId++;
            }

            for (int i = 0; i < allEngines.Count; ++i)
            {
                maxMach = Mathf.Max(maxMach, allEngines[i].maxMach);
            }

            UpdateActiveEngines();

            // Now that all the PartSims have been created we can do any set up that needs access to other parts
            // First we set up all the parent links
            for (int i = 0; i < allParts.Count; i++)
            {
                PartSim partSim = allParts[i];
                partSim.SetupParent(partSimLookup, log);
            }

            // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets
            if (HighLogic.LoadedSceneIsEditor)
            {
                for (int i = 0; i < allFuelLines.Count; ++i)
                {
                    PartSim partSim = allFuelLines[i];

                    CModuleFuelLine fuelLine = partSim.part.GetModule <CModuleFuelLine>();
                    if (fuelLine.target != null)
                    {
                        PartSim targetSim;
                        if (partSimLookup.TryGetValue(fuelLine.target, out targetSim))
                        {
                            if (log != null)
                            {
                                log.AppendLine("Fuel line target is ", targetSim.name, ":", targetSim.partId);
                            }

                            targetSim.fuelTargets.Add(partSim.parent);
                        }
                        else
                        {
                            if (log != null)
                            {
                                log.AppendLine("No PartSim for fuel line target (", partSim.part.partInfo.name, ")");
                            }
                        }
                    }
                    else
                    {
                        if (log != null)
                        {
                            log.AppendLine("Fuel line target is null");
                        }
                    }
                }
            }

            if (log != null)
            {
                log.AppendLine("SetupAttachNodes and count stages");
            }
            for (int i = 0; i < allParts.Count; ++i)
            {
                PartSim partSim = allParts[i];

                partSim.SetupAttachNodes(partSimLookup, log);
                if (partSim.decoupledInStage >= lastStage)
                {
                    lastStage = partSim.decoupledInStage + 1;
                }
            }

            // And finally release the Part references from all the PartSims
            if (log != null)
            {
                log.AppendLine("ReleaseParts");
            }
            for (int i = 0; i < allParts.Count; ++i)
            {
                allParts[i].ReleasePart();
            }

            // And dereference the core's part list
            partList = null;

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

            Dump();
            log = null;

            return(true);
        }
Beispiel #9
0
        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log)
        {
            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(part);
            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + name);

                foreach (PartModule partMod in part.Modules)
                {
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }

                log.buf.AppendLine("correctThrust = " + correctThrust);
            }

            if (hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                string mode = part.GetModule<MultiModeEngine>().mode;

                foreach (ModuleEnginesFX engine in part.GetModules<ModuleEnginesFX>())
                {
                    if (engine.engineID == mode)
                    {
                        if (log != null)
                            log.buf.AppendLine("Module: " + engine.moduleName);

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else
            {
                if (hasModuleEnginesFX)
                {
                    foreach (ModuleEnginesFX engine in part.GetModules<ModuleEnginesFX>())
                    {
                        if (log != null)
                            log.buf.AppendLine("Module: " + engine.moduleName);

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }

                if (hasModuleEngines)
                {
                    foreach (ModuleEngines engine in part.GetModules<ModuleEngines>())
                    {
                        if (log != null)
                            log.buf.AppendLine("Module: " + engine.moduleName);

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }
            }

            if (log != null)
                log.Flush();
        }
Beispiel #10
0
        public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
        {
            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(part);
            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + this.name);
                for (int i = 0; i < this.part.Modules.Count; i++)
                {
                    PartModule partMod = this.part.Modules[i];
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }

                log.buf.AppendLine("correctThrust = " + correctThrust);
            }

            if (hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                string mode = part.GetModule<MultiModeEngine>().mode;

                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) log.buf.AppendLine("Module: " + engine.moduleName);

                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = EngineSim.New(
                            this,
                            atmosphere,
                            (float)mach,
                            engine.maxFuelFlow,
                            engine.minFuelFlow,
                            engine.thrustPercentage,
                            thrustvec,
                            engine.atmosphereCurve,
                            engine.atmChangeFlow,
                            engine.useAtmCurve ? engine.atmCurve : null,
                            engine.useVelCurve ? engine.velCurve : null,
                            fullThrust ? 0.0f : engine.currentThrottle,
                            engine.g,
                            engine.throttleLocked,
                            engine.propellants,
                            engine.isOperational,
                            engine.resultingThrust,
                            engine.thrustTransforms,
                            log);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else
            {
                if (hasModuleEngines)
                {
                    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);

                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = EngineSim.New(
                            this,
                            atmosphere,
                            (float)mach,
                            engine.maxFuelFlow,
                            engine.minFuelFlow,
                            engine.thrustPercentage,
                            thrustvec,
                            engine.atmosphereCurve,
                            engine.atmChangeFlow,
                            engine.useAtmCurve ? engine.atmCurve : null,
                            engine.useVelCurve ? engine.velCurve : null,
                            fullThrust ? 0.0f : engine.currentThrottle,
                            engine.g,
                            engine.throttleLocked,
                            engine.propellants,
                            engine.isOperational,
                            engine.resultingThrust,
                            engine.thrustTransforms,
                            log);
                        allEngines.Add(engineSim);
                    }
                }
            }

            if (log != null)
            {
                log.Flush();
            }
        }
Beispiel #11
0
        public void CreateEngineSims(List <EngineSim> allEngines, double atmosphere, double velocity, bool vectoredThrust, LogMsg log)
        {
            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(part);

            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + name);

                foreach (PartModule partMod in part.Modules)
                {
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }

                log.buf.AppendLine("correctThrust = " + correctThrust);
            }

            if (hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                string mode = part.GetModule <MultiModeEngine>().mode;

                foreach (ModuleEnginesFX engine in part.GetModules <ModuleEnginesFX>())
                {
                    if (engine.engineID == mode)
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else
            {
                if (hasModuleEnginesFX)
                {
                    foreach (ModuleEnginesFX engine in part.GetModules <ModuleEnginesFX>())
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }

                if (hasModuleEngines)
                {
                    foreach (ModuleEngines engine in part.GetModules <ModuleEngines>())
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        Vector3 thrustvec = CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = new EngineSim(this,
                                                            atmosphere,
                                                            velocity,
                                                            engine.maxThrust,
                                                            engine.minThrust,
                                                            engine.thrustPercentage,
                                                            engine.requestedThrust,
                                                            thrustvec,
                                                            engine.realIsp,
                                                            engine.atmosphereCurve,
                                                            engine.useVelocityCurve ? engine.velocityCurve : null,
                                                            engine.throttleLocked,
                                                            engine.propellants,
                                                            engine.isOperational,
                                                            correctThrust);
                        allEngines.Add(engineSim);
                    }
                }
            }

            if (log != null)
            {
                log.Flush();
            }
        }
Beispiel #12
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();

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

                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();

                // Store various things in the Stage object
                stage.thrust = totalStageThrust;
                stage.thrustToWeight = totalStageThrust / (stageStartMass * gravity);
                stage.maxThrustToWeight = stage.thrustToWeight;
                stage.actualThrust = totalStageActualThrust;
                stage.actualThrustToWeight = totalStageActualThrust / (stageStartMass * gravity);
                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;

                    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 * Units.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;
                }

                // 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 / (Units.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].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;
        }
Beispiel #13
0
        // This function prepares the simulation by creating all the necessary data structures it will
        // need during the simulation.  All required data is copied from the core game data structures
        // so that the simulation itself can be run in a background thread without having issues with
        // the core game changing the data while the simulation is running.
        public bool PrepareSimulation(LogMsg _log, List<Part> parts, double theGravity, double theAtmosphere = 0, double theMach = 0, bool dumpTree = false, bool vectoredThrust = false, bool fullThrust = false)
        {
            log = _log;
            if (log != null) log.AppendLine("PrepareSimulation started");

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

            // Store the parameters in members for ease of access in other functions
            partList = parts;
            gravity = theGravity;
            atmosphere = theAtmosphere;
            mach = theMach;
            lastStage = StageManager.LastStage;
            maxMach = 1.0f;
            if (log != null) log.AppendLine("lastStage = ", lastStage);

            // Clear the lists for our simulation parts
            allParts.Clear();
            allFuelLines.Clear();
            drainingParts.Clear();
            allEngines.Clear();
            activeEngines.Clear();
            drainingResources.Clear();

            // A dictionary for fast lookup of Part->PartSim during the preparation phase
            partSimLookup.Clear();

            if (partList.Count > 0 && partList[0].vessel != null)
            {
                vesselName = partList[0].vessel.vesselName;
                vesselType = partList[0].vessel.vesselType;
            }
            // First we create a PartSim for each Part (giving each a unique id)
            int partId = 1;
            for (int i = 0; i < partList.Count; ++i)
            {
                Part part = partList[i];

                // If the part is already in the lookup dictionary then log it and skip to the next part
                if (partSimLookup.ContainsKey(part))
                {
                    if (log != null) log.AppendLine("Part ", part.name, " appears in vessel list more than once");
                    continue;
                }

                // Create the PartSim
                PartSim partSim = PartSim.New(part, partId, atmosphere, log);

                // Add it to the Part lookup dictionary and the necessary lists
                partSimLookup.Add(part, partSim);
                allParts.Add(partSim);
                if (partSim.isFuelLine)
                {
                    allFuelLines.Add(partSim);
                }
                if (partSim.isEngine)
                {
                    partSim.CreateEngineSims(allEngines, atmosphere, mach, vectoredThrust, fullThrust, log);
                }

                partId++;
            }

            for (int i = 0; i < allEngines.Count; ++i)
            {
                maxMach = Mathf.Max(maxMach, allEngines[i].maxMach);
            }

            UpdateActiveEngines();

            // Now that all the PartSims have been created we can do any set up that needs access to other parts
            // First we set up all the parent links
            for (int i = 0; i < allParts.Count; i++)
            {
                PartSim partSim = allParts[i];
                partSim.SetupParent(partSimLookup, log);
            }

            // Then, in the VAB/SPH, we add the parent of each fuel line to the fuelTargets list of their targets
            if (HighLogic.LoadedSceneIsEditor)
            {
                for (int i = 0; i < allFuelLines.Count; ++i)
                {
                    PartSim partSim = allFuelLines[i];

                    CModuleFuelLine fuelLine = partSim.part.GetModule<CModuleFuelLine>();
                    if (fuelLine.target != null)
                    {
                        PartSim targetSim;
                        if (partSimLookup.TryGetValue(fuelLine.target, out targetSim))
                        {
                            if (log != null) log.AppendLine("Fuel line target is ", targetSim.name, ":", targetSim.partId);

                            targetSim.fuelTargets.Add(partSim.parent);
                        }
                        else
                        {
                            if (log != null) log.AppendLine("No PartSim for fuel line target (", partSim.part.partInfo.name, ")");
                        }
                    }
                    else
                    {
                        if (log != null) log.AppendLine("Fuel line target is null");
                    }
                }
            }

            if (log != null) log.AppendLine("SetupAttachNodes and count stages");
            for (int i = 0; i < allParts.Count; ++i)
            {
                PartSim partSim = allParts[i];

                partSim.SetupAttachNodes(partSimLookup, log);
                if (partSim.decoupledInStage >= lastStage)
                {
                    lastStage = partSim.decoupledInStage + 1;
                }
            }

            // And finally release the Part references from all the PartSims
            if (log != null) log.AppendLine("ReleaseParts");
            for (int i = 0; i < allParts.Count; ++i)
            {
                allParts[i].ReleasePart();
            }

            // And dereference the core's part list
            partList = null;

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

            Dump();
            log = null;

            return true;
        }
Beispiel #14
0
        public void CreateEngineSims(List <EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
        {
            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + this.name);
                for (int i = 0; i < this.part.Modules.Count; i++)
                {
                    PartModule partMod = this.part.Modules[i];
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }
            }

            if (hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEngines but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEngines that is active
                string mode = part.GetModule <MultiModeEngine>().mode;

                List <ModuleEngines> engines = part.GetModules <ModuleEngines>();
                for (int i = 0; i < engines.Count; ++i)
                {
                    ModuleEngines engine = engines[i];
                    if (engine.engineID == mode)
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        EngineSim engineSim = EngineSim.New(
                            this,
                            engine,
                            atmosphere,
                            (float)mach,
                            vectoredThrust,
                            fullThrust,
                            log);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else if (hasModuleEngines)
            {
                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);
                    }

                    EngineSim engineSim = EngineSim.New(
                        this,
                        engine,
                        atmosphere,
                        (float)mach,
                        vectoredThrust,
                        fullThrust,
                        log);
                    allEngines.Add(engineSim);
                }
            }

            if (log != null)
            {
                log.Flush();
            }
        }
Beispiel #15
0
        public void CreateEngineSims(List <EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
        {
            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(this.part);

            if (log != null)
            {
                log.buf.AppendLine("CreateEngineSims for " + this.name);
                for (int i = 0; i < this.part.Modules.Count; i++)
                {
                    PartModule partMod = this.part.Modules[i];
                    log.buf.AppendLine("Module: " + partMod.moduleName);
                }

                log.buf.AppendLine("correctThrust = " + correctThrust);
            }

            if (this.hasMultiModeEngine)
            {
                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
                string mode = this.part.GetModule <MultiModeEngine>().mode;

                List <ModuleEnginesFX> enginesFx = this.part.GetModules <ModuleEnginesFX>();
                for (int i = 0; i < enginesFx.Count; i++)
                {
                    ModuleEnginesFX engine = enginesFx[i];
                    if (engine.engineID == mode)
                    {
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = EngineSim.New(
                            this,
                            atmosphere,
                            mach,
                            engine.maxFuelFlow,
                            engine.minFuelFlow,
                            engine.thrustPercentage,
                            thrustvec,
                            engine.atmosphereCurve,
                            engine.atmChangeFlow,
                            engine.useAtmCurve ? engine.atmCurve : null,
                            engine.useVelCurve ? engine.velCurve : null,
                            engine.currentThrottle,
                            engine.g,
                            engine.throttleLocked || fullThrust,
                            engine.propellants,
                            engine.isOperational,
                            correctThrust,
                            engine.thrustTransforms);
                        allEngines.Add(engineSim);
                    }
                }
            }
            else
            {
                if (this.hasModuleEngines)
                {
                    List <ModuleEngines> engines = this.part.GetModules <ModuleEngines>();  // only place that still allocate some memory
                    for (int i = 0; i < engines.Count; i++)
                    {
                        ModuleEngines engine = engines[i];
                        if (log != null)
                        {
                            log.buf.AppendLine("Module: " + engine.moduleName);
                        }

                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);

                        EngineSim engineSim = EngineSim.New(
                            this,
                            atmosphere,
                            mach,
                            engine.maxFuelFlow,
                            engine.minFuelFlow,
                            engine.thrustPercentage,
                            thrustvec,
                            engine.atmosphereCurve,
                            engine.atmChangeFlow,
                            engine.useAtmCurve ? engine.atmCurve : null,
                            engine.useVelCurve ? engine.velCurve : null,
                            engine.currentThrottle,
                            engine.g,
                            engine.throttleLocked || fullThrust,
                            engine.propellants,
                            engine.isOperational,
                            correctThrust,
                            engine.thrustTransforms);
                        allEngines.Add(engineSim);
                    }
                }
            }

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