public SimulationManager() { Stages = new Stage[0]; LastStage = new Stage(); Gravity = 9.81d; Atmosphere = 0d; }
private void DrawTWR(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(90)); GUILayout.Label("TWR (Max)", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(EngineerTools.SimpleFormatter(stages[i].thrustToWeight, "", 2) + " (" + EngineerTools.SimpleFormatter(stages[i].maxThrustToWeight, "", 2) + ")", dataStyle); } GUILayout.EndVertical(); }
private void DrawTime(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(60)); GUILayout.Label("TIME", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(Tools.FormatTime(stages[i].time), dataStyle); } GUILayout.EndVertical(); }
private void DrawThrust(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(85)); GUILayout.Label("THRUST", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(EngineerTools.ForceFormatter(stages[i].thrust), dataStyle); } GUILayout.EndVertical(); }
private void DrawStage(Stage[] stages) { GUILayout.BeginVertical(); GUILayout.Label(""); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label("S " + i, headingStyle); } GUILayout.EndVertical(); }
private void DrawMass(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(150)); GUILayout.Label("MASS", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(EngineerTools.WeightFormatter(stages[i].mass, stages[i].totalMass), dataStyle); } GUILayout.EndVertical(); }
private void DrawIsp(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(50)); GUILayout.Label("ISP", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(EngineerTools.SimpleFormatter(stages[i].isp, "s"), dataStyle); } GUILayout.EndVertical(); }
private void DrawDeltaV(Stage[] stages) { GUILayout.BeginVertical(GUILayout.Width(115)); GUILayout.Label("DELTA-V", headingStyle); for (int i = 0; i < stages.Length; i++) { if (!settings.Get<bool>("_SAVEONCHANGE_SHOW_ALL_STAGES") && stages[i].deltaV == 0) { continue; } GUILayout.Label(EngineerTools.SimpleFormatter(stages[i].deltaV, stages[i].inverseTotalDeltaV, "m/s"), dataStyle); } GUILayout.EndVertical(); }
// This function runs the simulation and returns a newly created array of Stage objects public Stage[] RunSimulation() { if (SimManager.logOutput) MonoBehaviour.print("RunSimulation started"); _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; LogMsg log = null; if (SimManager.logOutput) log = new LogMsg(); // 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 foreach (EngineSim engine in allEngines) { if (log != null) log.buf.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.buf.AppendLine("bActive = " + bActive + " bStage = " + bStage); if (HighLogic.LoadedSceneIsFlight) { if (bActive != bStage) { // If the active state is different to the state due to staging if (log != null) log.buf.AppendLine("Need to do current active engines first"); doingCurrent = true; currentStage++; break; } } else { if (bStage) { if (log != null) log.buf.AppendLine("Marking as active"); engine.isActive = true; } } } if (log != null) log.Flush(); // Create the array of stages that will be returned Stage[] stages = new Stage[currentStage + 1]; // Loop through the stages while (currentStage >= 0) { if (log != null) { log.buf.AppendLine("Simulating stage " + currentStage); log.buf.AppendLine("ShipMass = " + ShipMass); log.Flush(); _timer.Reset(); _timer.Start(); } // Update active engines and resource drains UpdateResourceDrains(); // Create the Stage object for this stage Stage stage = new Stage(); stageTime = 0d; vecStageDeltaV = Vector3.zero; stageStartMass = ShipMass; stepStartMass = stageStartMass; stepEndMass = 0; CalculateThrustAndISP(); // Store various things in the Stage object stage.thrust = totalStageThrust; //MonoBehaviour.print("stage.thrust = " + stage.thrust); stage.thrustToWeight = totalStageThrust / (stageStartMass * gravity); stage.maxThrustToWeight = stage.thrustToWeight; //MonoBehaviour.print("StageMass = " + stageStartMass); //MonoBehaviour.print("Initial maxTWR = " + stage.maxThrustToWeight); stage.actualThrust = totalStageActualThrust; stage.actualThrustToWeight = totalStageActualThrust / (stageStartMass * gravity); // Calculate the cost and mass of this stage foreach (PartSim partSim in allParts) { if (partSim.decoupledInStage == currentStage - 1) { stage.cost += partSim.cost; stage.mass += partSim.GetStartMass(); } } if (log != null) MonoBehaviour.print("Stage setup took " + _timer.ElapsedMilliseconds + "ms"); // Now we will loop until we are allowed to stage int loopCounter = 0; while (!AllowedToStage()) { loopCounter++; //MonoBehaviour.print("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(); if (time < resourceDrainTime) { resourceDrainTime = time; partMinDrain = partSim; } } if (log != null) MonoBehaviour.print("Drain time = " + resourceDrainTime + " (" + partMinDrain.name + ":" + partMinDrain.partId + ")"); foreach (PartSim partSim in drainingParts) partSim.DrainResources(resourceDrainTime); // Get the mass after draining stepEndMass = ShipMass; stageTime += resourceDrainTime; double stepEndTWR = totalStageThrust / (stepEndMass * gravity); //MonoBehaviour.print("After drain mass = " + stepEndMass); //MonoBehaviour.print("currentThrust = " + totalStageThrust); //MonoBehaviour.print("currentTWR = " + stepEndTWR); if (stepEndTWR > stage.maxThrustToWeight) stage.maxThrustToWeight = stepEndTWR; //MonoBehaviour.print("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 * STD_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) { MonoBehaviour.print("exceeded loop count"); MonoBehaviour.print("stageStartMass = " + stageStartMass); MonoBehaviour.print("stepStartMass = " + stepStartMass); MonoBehaviour.print("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; // 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 / (STD_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 stages[currentStage] = stage; // Now activate the next stage currentStage--; doingCurrent = false; if (log != null) { // Log how long the stage took _timer.Stop(); MonoBehaviour.print("Simulating stage took " + _timer.ElapsedMilliseconds + "ms"); stage.Dump(); _timer.Reset(); _timer.Start(); } // Activate the next stage ActivateStage(); if (log != null) { // Log how long it took to activate _timer.Stop(); MonoBehaviour.print("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].totalCost += stages[j].cost; stages[i].totalMass += stages[j].mass; stages[i].totalDeltaV += stages[j].deltaV; stages[i].totalTime += stages[j].time; } // 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; } if (log != null) { _timer.Stop(); MonoBehaviour.print("RunSimulation: " + _timer.ElapsedMilliseconds + "ms"); } return stages; }
public Stage[] RunSimulation(double gravity, double atmosphere = 0) { currentStage = Staging.lastStage; Stage[] stages = new Stage[currentStage + 1]; BuildVessel(this.partList, atmosphere); while (currentStage >= 0) { Stage stage = new Stage(); double stageTime = 0d; double stageDeltaV = 0d; double totalStageThrust = 0d; double totalStageActualThrust = 0d; double totalStageFlowRate = 0d; double totalStageIspFlowRate = 0d; foreach (PartSim engine in ActiveEngines) { totalStageActualThrust += engine.actualThrust; totalStageThrust += engine.thrust; totalStageFlowRate += engine.ResourceConsumptions.Mass; totalStageIspFlowRate += engine.ResourceConsumptions.Mass * engine.isp; } if (totalStageFlowRate > 0d && totalStageIspFlowRate > 0d) { stage.isp = totalStageIspFlowRate / totalStageFlowRate; } stage.thrust = totalStageThrust; stage.thrustToWeight = (double)(totalStageThrust / (ShipMass * gravity)); stage.actualThrust = totalStageActualThrust; stage.actualThrustToWeight = (double)(totalStageActualThrust / (ShipMass * gravity)); foreach (PartSim partSim in partSims) { if (partSim.decoupledInStage == currentStage - 1) { stage.cost += partSim.part.partInfo.cost; stage.mass += partSim.GetStartMass(currentStage); } } int loopCounter = 0; while (!AllowedToStage()) { loopCounter++; List<PartSim> engines = ActiveEngines; totalStageThrust = 0d; foreach (PartSim engine in engines) { if (engine.actualThrust > 0d) { totalStageThrust += engine.actualThrust; } else { totalStageThrust += engine.thrust; } } SetResourceDrainRates(); double resourceDrainTime = double.MaxValue; foreach (PartSim partSim in partSims) { double time = 0d; time = partSim.TimeToDrainResource(); if (time < resourceDrainTime) { resourceDrainTime = time; } } double startMass = ShipMass; foreach (PartSim partSim in partSims) { partSim.DrainResources(resourceDrainTime); } double endMass = ShipMass; stageTime += resourceDrainTime; if (resourceDrainTime > 0d && startMass > endMass && startMass > 0d && endMass > 0d) { stageDeltaV += (stage.isp * STD_GRAVITY) * Math.Log(startMass / endMass); } if (loopCounter == 1000) { break; } } stage.deltaV = stageDeltaV; if (stageTime < 9999) { stage.time = stageTime; } else { stage.time = 0d; } stages[currentStage] = stage; currentStage--; ActivateStage(); } for (int i = 0; i < stages.Length; i++) { for (int j = i; j >= 0; j--) { stages[i].totalCost += stages[j].cost; stages[i].totalMass += stages[j].mass; stages[i].totalDeltaV += stages[j].deltaV; stages[i].totalTime += stages[j].time; } for (int j = i; j < stages.Length; j++) { stages[i].inverseTotalDeltaV += stages[j].deltaV; } if (stages[i].totalTime > 9999d) { stages[i].totalTime = 0d; } } return stages; }