diff --git a/Models/EnergyData.cs b/Models/EnergyData.cs
index 901ff8b..6a3b602 100644
--- a/Models/EnergyData.cs
+++ b/Models/EnergyData.cs
@@ -4,12 +4,9 @@ namespace BattSim.Models
{
public class EnergyData
{
- public DateOnly Date { get; set; }
- public double DayConsumption { get; set; }
- public double NightConsumption { get; set; }
- public double TotalConsumption => DayConsumption + NightConsumption;
- public double DayProduction { get; set; }
- public double NightProduction { get; set; }
- public double TotalProduction => DayProduction + NightProduction;
+ public DateTime Time { get; set; }
+ public bool DayTarif { get; set; }
+ public double Consumption { get; set; }
+ public double Production { get; set; }
}
}
\ No newline at end of file
diff --git a/Pages/Home.razor b/Pages/Home.razor
index d288cfc..323a1a9 100644
--- a/Pages/Home.razor
+++ b/Pages/Home.razor
@@ -14,10 +14,10 @@
@if (_isLoadingFile){
Loading...
}
@if (EnergyData.Length != 0){
-
+
-
+
@@ -30,16 +30,7 @@
}
-
-Simulate Battery
-Set the battery capacity
-
-
-
-Calculate Cost
-
-
-@code {
+@code{
EnergyData[] EnergyData = [];
bool _isLoadingFile = false;
@@ -72,24 +63,29 @@
}
}
- bool _showProduction = true;
- bool _showConsumption = true;
-
private void OnSeriesClick(){}
private string FormatObject(object value) {
if(value is double d) return $"{value:0.##} kWh";
if(value is DateOnly date) return (date.Day == 1) ? date.ToString("MM/yyyy") : string.Empty;
else return string.Empty;
}
+}
+Simulate Battery
+Set the battery capacity
+
+
+
+Calculate Cost
+
+
+@code {
double BatteryCapacity = 0.0;
BatteryDayResult[] SimulationData = [];
-
private async Task SimulateBattery(){
Console.WriteLine("Simulating...");
SimulationData = BatterySimulator.SimulateBattery(EnergyData, BatteryCapacity).ToArray();
Console.WriteLine("Done simulating!");
}
-
}
\ No newline at end of file
diff --git a/Pages/Test.razor b/Pages/Test.razor
deleted file mode 100644
index b0eca29..0000000
--- a/Pages/Test.razor
+++ /dev/null
@@ -1,96 +0,0 @@
-@page "/Test"
-@using Radzen
-@using Radzen.Blazor
-@using System.Globalization
-
-
-Home
-
-Hello, world!
-
-Welcome to your new app.
-
-A Radzen chart:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-@code {
- bool showDataLabels = false;
-
- void OnSeriesClick(SeriesClickEventArgs args)
- {
-
- }
-
- class DataItem
- {
- public string Quarter { get; set; }
- public double Revenue { get; set; }
- }
-
- string FormatAsUSD(object value)
- {
- return ((double)value).ToString("C0", CultureInfo.CreateSpecificCulture("en-US"));
- }
-
- DataItem[] revenue2023 = new DataItem[]
- {
- new DataItem
- {
- Quarter = "Q1",
- Revenue = 234000
- },
- new DataItem
- {
- Quarter = "Q2",
- Revenue = 284000
- },
- new DataItem
- {
- Quarter = "Q3",
- Revenue = 274000
- },
- new DataItem
- {
- Quarter = "Q4",
- Revenue = 294000
- },
- };
-
- DataItem[] revenue2024 = new DataItem[] {
- new DataItem
- {
- Quarter = "Q1",
- Revenue = 254000
- },
- new DataItem
- {
- Quarter = "Q2",
- Revenue = 324000
- },
- new DataItem
- {
- Quarter = "Q3",
- Revenue = 354000
- },
- new DataItem
- {
- Quarter = "Q4",
- Revenue = 394000
- },
-
- };
-}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
index 4a31976..13fc4e3 100644
--- a/Program.cs
+++ b/Program.cs
@@ -4,8 +4,6 @@ using Radzen;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
-
-
// Setup Frontend
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add("#app");
@@ -14,4 +12,5 @@ builder.RootComponents.Add("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddRadzenComponents();
+
await builder.Build().RunAsync();
\ No newline at end of file
diff --git a/Services/BatterySimulator.cs b/Services/BatterySimulator.cs
index 6867963..7bc1811 100644
--- a/Services/BatterySimulator.cs
+++ b/Services/BatterySimulator.cs
@@ -12,31 +12,29 @@ namespace BattSim.Services
foreach (var day in data)
{
- // Charge battery from production
- var totalProduction = day.DayProduction + day.NightProduction;
- var chargedEnergy = System.Math.Min(totalProduction, batteryCapacity);
- var excessProduction = totalProduction - chargedEnergy;
+ // // Charge battery from production
+ // var chargedEnergy = System.Math.Min(day.TotalProduction, batteryCapacity);
+ // var excessProduction = day.TotalProduction - chargedEnergy;
- // Use battery for consumption
- var totalConsumption = day.DayConsumption + day.NightConsumption;
- var usedEnergy = System.Math.Min(chargedEnergy + remainingEnergy, totalConsumption);
- var remainingAfterUse = chargedEnergy + remainingEnergy - usedEnergy;
+ // // 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, totalConsumption);
- var reducedProduction = totalProduction - chargedEnergy;
+ // // 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
- });
+ // results.Add(new BatteryDayResult
+ // {
+ // Date = day.Date,
+ // ChargedEnergy = chargedEnergy,
+ // UsedEnergy = usedEnergy,
+ // RemainingEnergy = remainingAfterUse,
+ // ReducedConsumption = reducedConsumption,
+ // ReducedProduction = reducedProduction
+ // });
- remainingEnergy = remainingAfterUse;
+ // remainingEnergy = remainingAfterUse;
}
return results;
diff --git a/Services/DataLoader.cs b/Services/DataLoader.cs
index 41c9f2b..3b0fc18 100644
--- a/Services/DataLoader.cs
+++ b/Services/DataLoader.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -13,61 +14,85 @@ namespace BattSim.Services
{
public static async Task> LoadAndProcessData(IBrowserFile file)
{
- var energyData = new List();
- await using var stream = file.OpenReadStream();
- using var reader = new StreamReader(stream);
+ var energyData = new ConcurrentBag(); // Thread-safe collection
+ await using var stream = file.OpenReadStream(maxAllowedSize: (int)1.0e9);
+ using var reader = new StreamReader(stream, bufferSize: (int)1.0e6);
// Skip header
await reader.ReadLineAsync();
+ // Read all lines into memory
+ var lines = new List();
string line;
- while ((line = await reader.ReadLineAsync()) != null)
+ while ((line = await reader.ReadLineAsync()) is not null)
{
- var parts = line.Split(';');
- if (parts.Length < 9)
- {
- Console.WriteLine($"Skipping malformed line: {line}");
- continue;
- }
+ lines.Add(line);
+ }
+ // Process lines in parallel
+ Parallel.ForEach(lines, line =>
+ {
try
{
- var date = DateOnly.ParseExact(parts[0].Length == 10 ? parts[0] : "0"+parts[0], "dd/MM/yyyy", CultureInfo.InvariantCulture);
- var register = parts[7].Trim();
- var volumeStr = parts[8].Trim();
- var volume = string.IsNullOrEmpty(volumeStr)
- ? 0
- : double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
+ var parts = SplitLine(line);
+ DateTime time = ParseDateTime(parts[0..2]);
+ double volume = ParseVolume(parts[8]);
+ string register = parts[7].Trim();
+ bool dayTarif = register.Contains("Dag");
- var existing = energyData.FirstOrDefault(e => e.Date == date);
- if (existing == null)
- {
- existing = new EnergyData { Date = date };
- energyData.Add(existing);
- }
+ // Use ConcurrentBag for thread-safe additions
+ var entry = new EnergyData { Time = time, DayTarif = dayTarif };
+ if (register.Contains("Afname"))
+ entry.Consumption = volume;
+ else if (register.Contains("Injectie"))
+ entry.Production = volume;
+ else
+ throw new Exception("Unknown volume register");
- switch (register)
- {
- case "Afname Dag":
- existing.DayConsumption = volume;
- break;
- case "Afname Nacht":
- existing.NightConsumption = volume;
- break;
- case "Injectie Dag":
- existing.DayProduction = volume;
- break;
- case "Injectie Nacht":
- existing.NightProduction = volume;
- break;
- }
+ energyData.Add(entry);
}
- catch (Exception ex)
+ catch (Exception e)
{
- Console.WriteLine($"Error parsing line: {line}. Exception: {ex.Message}");
+ Console.WriteLine($"Error parsing line: {line}. Skipping to next line. Exception: {e}");
}
- }
- return energyData;
+ });
+
+ // Group by Time and merge entries
+ var groupedData = energyData
+ .GroupBy(e => e.Time)
+ .Select(g =>
+ {
+ var first = g.First();
+ first.Consumption = g.Sum(e => e.Consumption);
+ first.Production = g.Sum(e => e.Production);
+ return first;
+ })
+ .OrderBy(e => e.Time)
+ .ToList();
+
+ return groupedData;
}
-}
+
+ private static string[] SplitLine(string line)
+ {
+ var parts = line.Split(';');
+ if (parts.Length < 9)
+ throw new Exception($"Malformed line (too many parts): {line}");
+ return parts;
+ }
+
+ private static DateTime ParseDateTime(string[] dateTimeStrings)
+ {
+ string dateTimeString = dateTimeStrings[0] + " " + dateTimeStrings[1];
+ return DateTime.ParseExact(dateTimeString, "dd-MM-yyyy HH:mm:ss", CultureInfo.GetCultureInfo("nl-BE"));
+ }
+
+ private static double ParseVolume(string volumeString)
+ {
+ var volumeStr = volumeString.Trim();
+ return string.IsNullOrEmpty(volumeStr)
+ ? 0
+ : double.Parse(volumeStr.Replace(",", "."), CultureInfo.InvariantCulture);
+ }
+ }
}
\ No newline at end of file
diff --git a/Services/ReportGenerator.cs b/Services/ReportGenerator.cs
deleted file mode 100644
index 2e8d174..0000000
--- a/Services/ReportGenerator.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using BattSim.Models;
-
-namespace BattSim.Services
-{
- public class ReportGenerator
- {
- public static void GenerateReport(List originalData, Dictionary> scenarios)
- {
- using (var writer = new StreamWriter("../../../BatteryAnalysisReport.md"))
- {
- writer.WriteLine("# Battery Cost Analysis Report\n");
-
- // Original data summary
- writer.WriteLine("## Original Data Summary");
- var totalConsumption = originalData.Sum(d => d.DayConsumption + d.NightConsumption);
- var totalProduction = originalData.Sum(d => d.DayProduction + d.NightProduction);
- writer.WriteLine($"Total Consumption: {totalConsumption:F2} kWh");
- writer.WriteLine($"Total Production: {totalProduction:F2} kWh\n");
-
- // Generate graph data
- writer.WriteLine("### Energy Consumption and Production\n");
- writer.WriteLine("```");
- writer.WriteLine("Date,Total Production,Total Consumption");
- foreach (var day in originalData)
- {
- var prod = day.DayProduction + day.NightProduction;
- var cons = day.DayConsumption + day.NightConsumption;
- writer.WriteLine($"{day.Date:yyyy-MM-dd},{prod:F2},{cons:F2}");
- }
- writer.WriteLine("```\n");
-
- writer.WriteLine("");
- writer.WriteLine("(Graph showing total production in green and total consumption in red)\n");
-
- // Scenario analysis
- foreach (var scenario in scenarios)
- {
- var batteryCount = scenario.Key;
- var results = scenario.Value;
-
- writer.WriteLine($"## Scenario with {batteryCount} Battery{(batteryCount > 1 ? "ies" : "")}");
- writer.WriteLine($"Battery Capacity: {batteryCount * 2.6} kWh\n");
-
- var totalReducedConsumption = results.Sum(r => r.ReducedConsumption);
- var totalReducedProduction = results.Sum(r => r.ReducedProduction);
- var savings = totalReducedConsumption * 0.30; // Assuming €0.30 per kWh
-
- writer.WriteLine($"Total Reduced Consumption: {totalReducedConsumption:F2} kWh");
- writer.WriteLine($"Total Reduced Production: {totalReducedProduction:F2} kWh");
- writer.WriteLine($"Estimated Annual Savings: €{savings:F2}\n");
-
- // Generate scenario graph data
- writer.WriteLine($"### Battery Performance for {batteryCount} Battery{(batteryCount > 1 ? "ies" : "")}\n");
- writer.WriteLine("```");
- writer.WriteLine("Date,Charged Energy,Used Energy,Remaining Energy");
- foreach (var result in results)
- {
- writer.WriteLine($"{result.Date:yyyy-MM-dd},{result.ChargedEnergy:F2},{result.UsedEnergy:F2},{result.RemainingEnergy:F2}");
- }
- writer.WriteLine("```\n");
-
- writer.WriteLine($"");
- writer.WriteLine("(Graph showing charged energy in blue, used energy in orange, and remaining energy in gray)\n");
-
- // Detailed daily results
- writer.WriteLine("### Daily Results");
- writer.WriteLine("| Date | Charged (kWh) | Used (kWh) | Remaining (kWh) |");
- writer.WriteLine("|------|---------------|------------|-----------------|");
-
- foreach (var result in results.Take(10)) // Show first 10 days
- {
- writer.WriteLine($"| {result.Date:yyyy-MM-dd} | {result.ChargedEnergy:F2} | {result.UsedEnergy:F2} | {result.RemainingEnergy:F2} |");
- }
-
- writer.WriteLine("\n---\n");
- }
- }
-
- Console.WriteLine("Report generated: BatteryAnalysisReport.md");
- }
- }
-}
\ No newline at end of file
diff --git a/_Imports.razor b/_Imports.razor
index b9514d2..f240922 100644
--- a/_Imports.razor
+++ b/_Imports.razor
@@ -8,3 +8,4 @@
@using Microsoft.JSInterop
@using BattSim
@using BattSim.Layout
+@using Radzen.Blazor