using System.Collections.Concurrent; using System.Collections.Generic; using BattSim.Models; namespace BattSim.Services { public static class BatterySimulator { public static SimulatedBatteryEnergyData[] SimulateBattery(EnergyData[] energyData, double batteryCapacity, double efficiency) { var results = new List(); double batteryCharge = 0; foreach (var e in energyData) { var simulatedBatteryEnergyData = new SimulatedBatteryEnergyData(e); // Simulate charging the battery based on production double excessProduction = batteryCharge + e.Production - batteryCapacity; batteryCharge = double.Min(batteryCharge + e.Production, batteryCapacity); simulatedBatteryEnergyData.SimulatedProduction = double.Max(excessProduction, 0); // Simulate discharging the battery based on consumption double availableEnergy = batteryCharge * efficiency; double deficit = e.Consumption - availableEnergy; double energyDrawn = Math.Min(e.Consumption, availableEnergy); batteryCharge = batteryCharge - (energyDrawn / efficiency); // Adjust for loss simulatedBatteryEnergyData.SimulatedConsumption = Math.Max(deficit, 0); // Register the current charge simulatedBatteryEnergyData.BatteryCharge = batteryCharge; results.Add(simulatedBatteryEnergyData); } return results.ToArray(); } public static SimulatedBatteryEnergyData[] GenerateDailyData(SimulatedBatteryEnergyData[] simulationData) { var simulationDataCopy = (SimulatedBatteryEnergyData[]) simulationData.Clone(); var dailySimulationData = new ConcurrentDictionary(); Parallel.ForEach(simulationDataCopy, simulationPoint => { var date = DateOnly.FromDateTime(simulationPoint.Time); // Use AddOrUpdate to avoid double lookup dailySimulationData.AddOrUpdate( date, new SimulatedBatteryEnergyData(simulationPoint), // If key doesn't exist, add this value (_, existing) => { // If key exists, aggregate the values existing.Consumption += simulationPoint.Consumption; existing.Production += simulationPoint.Production; existing.SimulatedConsumption += simulationPoint.SimulatedConsumption; existing.SimulatedProduction += simulationPoint.SimulatedProduction; existing.BatteryCharge = double.Max(existing.BatteryCharge, simulationPoint.BatteryCharge); return existing; } ); }); return dailySimulationData.Values.ToArray(); } } }