public void TestInitialize() { _validator = new ProductionPlanValidator(); }
/// <summary> /// Calculate the output power for each powerplant in order to supply the requested load /// </summary> public IEnumerable <PowerPlantLoad> CalculateUnitCommitment(ProductionPlan productionPlan) { if (productionPlan == null) { _logger.LogError("The production plan should not be null"); throw new ArgumentNullException(nameof(productionPlan), "The production plan should not be null"); } var validator = new ProductionPlanValidator(); validator.ValidateAndThrow(productionPlan); // Create PowerPlantLoad and order it by merit order and maximum power var powerPlantLoadsByMeritOrder = productionPlan.PowerPlants .OrderBy(p => CalculatePricePerMWh(p, productionPlan.Fuels)) .ThenByDescending(p => p.PMax) .Select(p => new PowerPlantLoad(p.Name, p.Type, p.PMin, p.PMax, productionPlan.Fuels.WindPercentage, 0)) .ToList(); // Check if there is at least one powerplant which has a minimum power less than or equal to the requested load var smallestPMin = powerPlantLoadsByMeritOrder.Min(p => p.RealPMin); if (productionPlan.Load < smallestPMin) { throw new ImpossibleToSupplyException( productionPlan.Load, $"All powerplants have a PMin greater than the requested load (smallest PMin {smallestPMin})" ); } // Check if the maximum real power of all powerplants is greater than or equal to the requested load var totalPMaxPossible = powerPlantLoadsByMeritOrder.Sum(p => p.RealPMax); if (productionPlan.Load > totalPMaxPossible) { throw new ImpossibleToSupplyException( productionPlan.Load, $"The sum of all PMax is lesser than the requested load (total PMax {totalPMaxPossible})" ); } // Find best output power for each powerplant var remainingLoadToPlan = productionPlan.Load; for (var i = 0; i < powerPlantLoadsByMeritOrder.Count; i++) { var(power, newRemainingLoadToPlan) = CalculateOutputPowerPlant( powerPlantLoadsByMeritOrder[i], powerPlantLoadsByMeritOrder.Take(i), remainingLoadToPlan ); remainingLoadToPlan = newRemainingLoadToPlan; powerPlantLoadsByMeritOrder[i].ChangePower(power); // No more power to find if (remainingLoadToPlan == 0) { break; } } // If there is some remaining load, it's not possible to find a solution if (remainingLoadToPlan > 0) { throw new ImpossibleToSupplyException( productionPlan.Load, "No combination of powerplants allows to obtain it" ); } return(powerPlantLoadsByMeritOrder); }