Added quarter based simulation with efficiency and capacity parameters.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using BattSim.Models;
|
||||
|
||||
@@ -5,39 +6,59 @@ namespace BattSim.Services
|
||||
{
|
||||
public static class BatterySimulator
|
||||
{
|
||||
public static List<BatteryDayResult> SimulateBattery(EnergyData[] data, double batteryCapacity)
|
||||
public static SimulatedBatteryEnergyData[] SimulateBattery(EnergyData[] energyData, double batteryCapacity, double efficiency)
|
||||
{
|
||||
var results = new List<BatteryDayResult>();
|
||||
double remainingEnergy = 0;
|
||||
var results = new List<SimulatedBatteryEnergyData>();
|
||||
double batteryCharge = 0;
|
||||
|
||||
foreach (var day in data)
|
||||
foreach (var e in energyData)
|
||||
{
|
||||
// // Charge battery from production
|
||||
// var chargedEnergy = System.Math.Min(day.TotalProduction, batteryCapacity);
|
||||
// var excessProduction = day.TotalProduction - chargedEnergy;
|
||||
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);
|
||||
|
||||
// // Use battery for consumption
|
||||
// var usedEnergy = System.Math.Min(chargedEnergy + remainingEnergy, day.TotalConsumption);
|
||||
// var remainingAfterUse = chargedEnergy + remainingEnergy - usedEnergy;
|
||||
|
||||
// // Calculate reduced values
|
||||
// var reducedConsumption = System.Math.Min(usedEnergy, day.TotalConsumption);
|
||||
// var reducedProduction = day.TotalProduction - chargedEnergy;
|
||||
|
||||
// results.Add(new BatteryDayResult
|
||||
// {
|
||||
// Date = day.Date,
|
||||
// ChargedEnergy = chargedEnergy,
|
||||
// UsedEnergy = usedEnergy,
|
||||
// RemainingEnergy = remainingAfterUse,
|
||||
// ReducedConsumption = reducedConsumption,
|
||||
// ReducedProduction = reducedProduction
|
||||
// });
|
||||
|
||||
// remainingEnergy = remainingAfterUse;
|
||||
// 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;
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public static SimulatedBatteryEnergyData[] GenerateDailyData(SimulatedBatteryEnergyData[] simulationData)
|
||||
{
|
||||
var simulationDataCopy = (SimulatedBatteryEnergyData[]) simulationData.Clone();
|
||||
var dailySimulationData = new ConcurrentDictionary<DateOnly, SimulatedBatteryEnergyData>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace BattSim.Services
|
||||
{
|
||||
public static class FluviusDataHandler
|
||||
{
|
||||
public static async Task<Dictionary<DateTime, EnergyData>> LoadAndProcessFile(IBrowserFile file)
|
||||
public static async Task<EnergyData[]> LoadAndProcessFile(IBrowserFile file)
|
||||
{
|
||||
var lines = await ReadCsvFile(file);
|
||||
var energyData = new ConcurrentDictionary<DateTime,EnergyData>(); // Thread-safe collection
|
||||
@@ -48,21 +48,22 @@ namespace BattSim.Services
|
||||
Console.WriteLine($"Error parsing line: {line}. Skipping to next line. Exception: {e}");
|
||||
}
|
||||
});
|
||||
return energyData.ToDictionary();
|
||||
var results = energyData.Values.ToArray();
|
||||
results.Sort((a,b)=>a.Time.CompareTo(b.Time));
|
||||
return results;
|
||||
}
|
||||
|
||||
public static Dictionary<DateOnly, EnergyData> GenerateDailyData(Dictionary<DateTime, EnergyData> energyData)
|
||||
public static EnergyData[] GenerateDailyData(EnergyData[] energyData)
|
||||
{
|
||||
var dailyEnergyData = new ConcurrentDictionary<DateOnly, EnergyData>();
|
||||
Parallel.ForEach(energyData, entry =>
|
||||
Parallel.ForEach(energyData, energy =>
|
||||
{
|
||||
var date = DateOnly.FromDateTime(entry.Key);
|
||||
var energy = entry.Value;
|
||||
var date = DateOnly.FromDateTime(energy.Time);
|
||||
|
||||
// Use AddOrUpdate to avoid double lookup
|
||||
dailyEnergyData.AddOrUpdate(
|
||||
date,
|
||||
energy, // If key doesn't exist, add this value
|
||||
new EnergyData(energy), // If key doesn't exist, add this value
|
||||
(_, existing) =>
|
||||
{
|
||||
// If key exists, aggregate the values
|
||||
@@ -72,7 +73,7 @@ namespace BattSim.Services
|
||||
}
|
||||
);
|
||||
});
|
||||
return dailyEnergyData.ToDictionary();
|
||||
return dailyEnergyData.Values.ToArray();
|
||||
}
|
||||
|
||||
private static async Task<List<string>> ReadCsvFile(IBrowserFile file)
|
||||
|
||||
Reference in New Issue
Block a user