private static List <PowerPlantModel> CalculateCostAndMaxPower(PlanCommand request) { var powerPlantWithCosts = request.PowerPlants.Select(x => new PowerPlantModel { Name = x.Name, Type = x.Type, Efficiency = x.Efficiency, PMax = x.PMax, PMin = x.PMin, Power = GetMaxPower(x, request.Fuels), // the max power that a powerplant can generate Cost = GetCost(x, request.Fuels) // total cost }).ToList(); return(powerPlantWithCosts); }
public async Task <List <UnitCommitmentModel> > Handle(PlanCommand request, CancellationToken cancellationToken) { return(await Task.Run(() => { var uc = new List <UnitCommitmentModel>(); var expectedLoad = request.Load; var producedLoad = 0M; var powerPlantWithCosts = CalculateCostAndMaxPower(request); if (powerPlantWithCosts.Sum(x => x.Power) < request.Load) { throw new PlanCommandException("The expected load cannot be fulfilled"); } // merit-order var powerPlantsThatCanProducePower = powerPlantWithCosts.Where(x => x.Power > 0) .OrderBy(x => x.Cost) // privilege the cheapest and the more efficient (Efficiency is taken in account) .ThenByDescending(x => x.Power) .ThenBy(x => x.PMin); var powerPlantsThatCannotProducePower = powerPlantWithCosts.Where(x => x.Power <= 0); // Wind-turbine when % of wind = 0 foreach (var p in powerPlantsThatCanProducePower) { if (producedLoad < expectedLoad) { // calculate the power to generate var powerToGenerate = p.Power + producedLoad > expectedLoad ? (expectedLoad - producedLoad < p.PMin ? p.PMin : expectedLoad - producedLoad) : p.Power; // if we are note above the load if (producedLoad + powerToGenerate <= expectedLoad) { uc.Add(new UnitCommitmentModel() { Name = p.Name, Power = powerToGenerate }); producedLoad += powerToGenerate; } else { //The load is not yet reached and if we take the max power of the next powerplants in the list // we will exceed the expected load. // so the rest of load (to achieve the expected load) need to be balanced between the 2 lats poweplants var last = uc.Last(); uc.Remove(last); // adjust the amount of the power that powerplant should produce // taking in account the Pmin of the next powerplant that should be switched on var actualPower = uc.Sum(x => x.Power) + p.PMin; uc.Add(new UnitCommitmentModel() { Name = last.Name, Power = expectedLoad - actualPower }); uc.Add(new UnitCommitmentModel() { Name = p.Name, Power = p.PMin // take the minimum of the capacity when switched on (more expensive) }); } } else { // Should be switched off uc.Add(new UnitCommitmentModel() { Name = p.Name, Power = 0 }); } } // the powerplants that should not be switched on foreach (var p in powerPlantsThatCannotProducePower) { uc.Add(new UnitCommitmentModel() { Name = p.Name, Power = 0 }); } // TODO handle this case if (uc.Sum(x => x.Power) > request.Load) { // TODO } return uc; }, cancellationToken)); }