/// <summary> /// Applies a bounding function to the current capacity of the battery, to prohibit discharging below 0 joules, /// and the prevent charging above the maximum specified capabilities. If the battery exceeds the specification, /// a warning (for overcharge) or critical error (for discharged) will be logged to the solution. /// </summary> /// <param name="battery">The battery parameters to enforce.</param> /// <param name="pass">The last pass that was executed.</param> /// <returns>A value indicating whether the requested capacity could be accomplished successfully.</returns> private bool EnforceBatteryLimits(Battery battery, PassOrbit pass, IPassPhase phase) { var success = true; if (this.currentCapacityJoules < 0) { // Orbit parameters are impossible - we've run out of power. // Error is fatal - denote the problem and abort scheduling. this.solution.IsSolvable = false; this.solution.Problems.Add(new ScheduleSolution.SchedulerProblem( ScheduleSolution.SchedulerProblem.SeverityLevel.Fatal, $"Orbit parameters for {pass.Name} are impossible. No power remains while scheduling the {phase.PhaseName} for {pass.Name}.")); this.currentCapacityJoules = 0; // Discharging completely is a fatal error that will prevent the pass from completing success = false; } else if (this.currentCapacityJoules > battery.EffectiveCapacityJ) { this.solution.Problems.Add(new ScheduleSolution.SchedulerProblem( ScheduleSolution.SchedulerProblem.SeverityLevel.Warning, $"The battery was a contraint during {pass.Name}. {this.currentCapacityJoules:n} J were available, but max charge capacity is {battery.EffectiveCapacityJ:n} J")); // Apply the cap. this.currentCapacityJoules = battery.EffectiveCapacityJ; // Overcharging doesn't prevent the mission from continuing, but indicates inefficiency success = true; } return(success); }
/// <summary> /// Initializes a new instance of the <see cref="PassPhase"/> class. /// </summary> /// <param name="passPhaseToCopy">Phase to copy.</param> public PassPhase(IPassPhase passPhaseToCopy) { this.StartTime = passPhaseToCopy.StartTime; this.EndTime = passPhaseToCopy.EndTime; this.PhaseName = passPhaseToCopy.PhaseName; this.TotalEnergyUsed = passPhaseToCopy.TotalEnergyUsed; }
private bool FindProfileForPhase(SortedDictionary <double, IByteStreamProcessor> optimizationMap, PassOrbit pass, IPassPhase phase, long bytes) { var allowedTime = phase.EndTime.Subtract(phase.StartTime); // For the encryption phase, we have an abs max of currentCapacityJoules // and the time allocated to encryptionPhase. // Start with the most ideal profile and keep testing until we find one that fits var foundViableProfile = false; foreach (var profile in optimizationMap.Values) { var timeRequired = bytes / profile.BytesPerSecond; var energyRequired = bytes * profile.JoulesPerByte; if (timeRequired > allowedTime.TotalSeconds) { // Out of time foundViableProfile = false; } else if (energyRequired > this.currentCapacityJoules) { // Out of power foundViableProfile = false; } else { // This solution works for this part this.solution.ViableProfiles[pass][phase.PhaseName] = profile; phase.TotalEnergyUsed = energyRequired; foundViableProfile = true; this.currentCapacityJoules -= energyRequired; break; } } return(foundViableProfile); }