diff --git a/Zero_engine.alpx b/Zero_engine.alpx
index 604453f6..29de1bc0 100644
--- a/Zero_engine.alpx
+++ b/Zero_engine.alpx
@@ -1316,6 +1316,26 @@ LARGE_CONNECTION (grootverbruik, > 3x80)
+
+ 1782815749074
+
+
+
+
+
+
@@ -2271,6 +2291,11 @@ LARGE_CONNECTION (grootverbruik, > 3x80)
1764938574089
+
+ 1782811550548
+
+ 1752680962144
+
com.anylogic.libraries.modules.markup_descriptors
diff --git a/_alp/Agents/EnergyModel/AOC.EnergyModel.xml b/_alp/Agents/EnergyModel/AOC.EnergyModel.xml
index 9a63138c..07b7a330 100644
--- a/_alp/Agents/EnergyModel/AOC.EnergyModel.xml
+++ b/_alp/Agents/EnergyModel/AOC.EnergyModel.xml
@@ -50,7 +50,9 @@ import com.querydsl.core.types.dsl.TimeExpression;
//import zero_engine.J_EAStorageElectric;
//import zero_engine.J_EAConsumption;
-import com.anylogic.cloud.util.DateUtils;]]>
+import com.anylogic.cloud.util.DateUtils;
+
+import zero_engine.J_ActivityTrackerTrips.TripRecord;]]>
I_EnergyData
false
diff --git a/_alp/Agents/EnergyModel/Levels/Level.level.xml b/_alp/Agents/EnergyModel/Levels/Level.level.xml
index e80a2009..2b3bfccd 100644
--- a/_alp/Agents/EnergyModel/Levels/Level.level.xml
+++ b/_alp/Agents/EnergyModel/Levels/Level.level.xml
@@ -1419,4 +1419,121 @@ energyDataViewer.viewArea.navigateTo();
0
0
+
+ false
+ 1782465008753
+
+ 900
+ -320
+
+ true
+ true
+ false
+ SHAPE_DRAW_2D3D
+
+ false
+ -16777216
+ true
+ traceln("index of 1 jan: %s", p_timeParameters.getDayOfWeek1jan());
+traceln("day of 1 jan: %s", p_timeParameters.getDayFromDayIndex(p_timeParameters.getDayOfWeek1jan()));
+traceln("p_timeParameters.getDayOfWeek1jan(): %s", p_timeParameters.getDayOfWeek1jan());
+traceln("p_timeParameters.getWeekIndex(12): %s", p_timeParameters.getWeekIndex(12));
+traceln("p_timeParameters.getWeekIndex(36): %s", p_timeParameters.getWeekIndex(36));
+traceln("p_timeParameters.getWeekIndex(200): %s", p_timeParameters.getWeekIndex(200));
+traceln("p_timeParameters.getWeekStart_h(0): %s", p_timeParameters.getWeekStart_h(0));
+traceln("p_timeParameters.getWeekStart_h(1): %s", p_timeParameters.getWeekStart_h(1));
+traceln("p_timeParameters.getWeekStart_h(2): %s", p_timeParameters.getWeekStart_h(2));
+
+
+
+ Date
+
+
+
+ false
+ 1782475157232
+
+ 1040
+ -320
+
+ true
+ true
+ false
+ SHAPE_DRAW_2D3D
+
+ false
+ -16777216
+ true
+ //GridConnection GC = findFirst(c_gridConnections, gc -> gc.c_tripTrackers.size() > 0);
+GridConnection GC = findFirst(c_gridConnections, gc -> gc.p_gridConnectionID.equals("addressuid.school"));
+J_ActivityTrackerTrips tt = GC.c_tripTrackers.get(0);
+
+double startTime_h = 0;
+double endTime_h = 24+168;
+
+List<TripRecord> trips = tt.getTripsInRange(startTime_h, endTime_h);
+
+traceln(tt);
+
+for (TripRecord trip : trips) {
+ traceln("startTime: %s", trip.startTime_h());
+ traceln("endTime: %s", trip.endTime_h());
+ traceln("distance: %s", trip.distance_km());
+}
+
+
+
+ Trips
+
+
+
+ false
+ 1782826903548
+
+ 1180
+ -320
+
+ true
+ true
+ false
+ SHAPE_DRAW_2D3D
+
+ false
+ -16777216
+ true
+ //GridConnection GC = findFirst(c_gridConnections, gc -> gc.c_tripTrackers.size() > 0);
+GridConnection GC = findFirst(c_gridConnections, gc -> gc.p_gridConnectionID.equals("addressuid.school"));
+
+double timeOfIntervalStart_h = 0;
+double timeOfIntervalEnd_h = 48;
+
+Map<Class< ? extends I_AssetManagement>, J_AssetTypeForecast> map = GC.f_getForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h, p_timeParameters);
+
+J_AssetTypeForecast chargingForecast = map.get(I_ChargingManagement.class);
+
+traceln("chargingForecast: %s", chargingForecast);
+
+Double[] load = chargingForecast.load_kW().get(OL_EnergyCarriers.ELECTRICITY);
+
+traceln("load: ");
+for (int i = 0; i < timeOfIntervalEnd_h / p_timeParameters.getTimeStep_h(); i++) {
+ double t = timeOfIntervalStart_h + i * p_timeParameters.getTimeStep_h();
+ traceln("time t: %s, load: %s kW", t, load[i]);
+}
+
+
+
+
+ Forecaster
+
+
diff --git a/_alp/Agents/GridConnection/Code/Functions.java b/_alp/Agents/GridConnection/Code/Functions.java
index 965d67e5..a086a5a0 100644
--- a/_alp/Agents/GridConnection/Code/Functions.java
+++ b/_alp/Agents/GridConnection/Code/Functions.java
@@ -1242,3 +1242,14 @@ else if (heatingAsset instanceof J_EAConversionHeatPump heatPump) {
return nettoBalance_kW;
/*ALCODEEND*/}
+Map, J_AssetTypeForecast> f_getForecast(double timeOfIntervalStart_h,double timeOfIntervalEnd_h,J_TimeParameters timeParameters)
+{/*ALCODESTART::1782459765981*/
+if (p_energyManagement != null) {
+ return p_energyManagement.getFlexAssetForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h);
+}
+
+else {
+ return new HashMap, J_AssetTypeForecast>();
+}
+/*ALCODEEND*/}
+
diff --git a/_alp/Agents/GridConnection/Code/Functions.xml b/_alp/Agents/GridConnection/Code/Functions.xml
index 4b6e4235..9286fe58 100644
--- a/_alp/Agents/GridConnection/Code/Functions.xml
+++ b/_alp/Agents/GridConnection/Code/Functions.xml
@@ -1210,4 +1210,32 @@
+
+ RETURNS_VALUE
+ Map<Class< ? extends I_AssetManagement>, J_AssetTypeForecast>
+ 1782459765981
+
+ 1490
+ 480
+
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_alp/Classes/Class.I_AssetManagement.java b/_alp/Classes/Class.I_AssetManagement.java
index 4e6fc143..ff9c51a5 100644
--- a/_alp/Classes/Class.I_AssetManagement.java
+++ b/_alp/Classes/Class.I_AssetManagement.java
@@ -16,5 +16,5 @@ public interface I_AssetManagement extends I_StoreStatesAndReset
{
//Get the AssetManagementInterface type (I_ChargingManagement.class, I_Heatingmanagement.class, etc.)
Class extends I_AssetManagement> getAssetManagementInterfaceType();
-
+ J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h);
}
\ No newline at end of file
diff --git a/_alp/Classes/Class.I_EnergyManagement.java b/_alp/Classes/Class.I_EnergyManagement.java
index 1906faf9..6e015715 100644
--- a/_alp/Classes/Class.I_EnergyManagement.java
+++ b/_alp/Classes/Class.I_EnergyManagement.java
@@ -73,8 +73,28 @@ default boolean isAssetManagementSupported(Class assetManagementType) {
return getInternalAssetManagements().contains(assetManagementType) || getSupportedExternalAssetManagements().contains(assetManagementType);
}
+
+ default public Map, J_AssetTypeForecast> getFlexAssetForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map, J_AssetTypeForecast> forecasts = new HashMap, J_AssetTypeForecast>();
+ Map, I_AssetManagement> activeExternalManagements = this.getActiveExternalAssetManagements();
+ for (Class externalManagementClass : this.getSupportedExternalAssetManagements()) {
+ I_AssetManagement externalManagement = activeExternalManagements.get(externalManagementClass);
+ if (externalManagement != null) {
+ J_AssetTypeForecast forecast = externalManagement.getForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h);
+ forecasts.put(externalManagementClass, forecast);
+ }
+ }
+ for (Class internalManagementClass : this.getInternalAssetManagements()) {
+ J_AssetTypeForecast forecast = forecastInternalAssetType(internalManagementClass, timeOfIntervalStart_h, timeOfIntervalEnd_h);
+ forecasts.put(internalManagementClass, forecast);
+ }
+ return forecasts;
+ }
-
+ default J_AssetTypeForecast forecastInternalAssetType(Class extends I_AssetManagement> type, double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ throw new RuntimeException("EMS declares " + type.getSimpleName() + " as an internal asset management but does not override forecastInternalAssetType() to handle it.");
+ }
+
////Checks
//Check configuration: Should be called whenever a management or asset has been removed/added/changed.
default public void checkConfiguration(List flexAssetsGCList) {
diff --git a/_alp/Classes/Class.J_ActivityTrackerTrips.java b/_alp/Classes/Class.J_ActivityTrackerTrips.java
index d9f205a8..b534b90f 100644
--- a/_alp/Classes/Class.J_ActivityTrackerTrips.java
+++ b/_alp/Classes/Class.J_ActivityTrackerTrips.java
@@ -56,7 +56,7 @@ public J_ActivityTrackerTrips(TextFile tripsCSV, int CSVRowIndex, I_Vehicle vehi
// 'forward' to next activity
setStartIndex(timeVariables, chargePointRegistration);
- }
+ }
/**
* Constructor using defined trips as input
@@ -68,23 +68,19 @@ public J_ActivityTrackerTrips(List tripRecords, I_Vehicle vehicle, I
// 'forward' to next activity
setStartIndex(timeVariables, chargePointRegistration);
- }
+ }
- private double getTimeSinceWeekStart_h(double time_h) {
- double timeSinceWeekStart_h = (time_h + (timeParameters.getDayOfWeek1jan()-1) * 24) % (7*24);
- return timeSinceWeekStart_h;
- }
+ private double getTimeSinceWeekStart_h(double time_h) {
+ double timeSinceWeekStart_h = (time_h + (timeParameters.getDayOfWeek1jan()-1) * 24) % (7*24);
+ return timeSinceWeekStart_h;
+ }
- private void setNextTrip() {
- eventIndex++;
- if ( eventIndex > tripRecords.size() - 1 ) {
- eventIndex = 0;
- }
- }
-
-
-
-
+ private void setNextTrip() {
+ eventIndex++;
+ if ( eventIndex > tripRecords.size() - 1 ) {
+ eventIndex = 0;
+ }
+ }
/*
* Main method that is called every timestep.
@@ -93,128 +89,154 @@ private void setNextTrip() {
* If the vehicle is already on a trip it progresses the trip to check if the trip ends this timestep.
* If so, it also checks if a new trip is starting in that same timestep.
*/
- public void manageActivities(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
- double time_h = timeVariables.getT_h();
- double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h); // Trip start/end-times are all defined as minutes since monday 00:00h, trips are looped indefinitely
- if (vehicle.getAvailability()) { // at start of timestep! check for multiple 'events' in timestep!
- if ( timeSinceWeekStart_h >= tripRecords.get(eventIndex).startTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).startTime_h()) { // is a trip starting this timestep?
- currentTripTimesteps_n = max(1,roundToInt(((tripRecords.get(eventIndex).endTime_h() - tripRecords.get(eventIndex).startTime_h()) / (timeParameters.getTimeStep_h()))));
-
- vehicle.startTrip(timeVariables);
- if(vehicle instanceof J_EAEV EV) {
- chargePointRegistration.deregisterChargingRequest(EV);
- }
- if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).endTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).endTime_h()) { // is the trip also ending this timestep?
- vehicle.endTrip(tripDistance_km);
- setNextTrip();
- prepareNextActivity(timeVariables, chargePointRegistration);
- }
- }
- } else {
- if (vehicle instanceof J_EAFuelVehicle fuelVehicle) {
- fuelVehicle.progressTrip(tripDistance_km / currentTripTimesteps_n);
- }
- if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).endTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).endTime_h()) { // is a trip ending this timestep?
- vehicle.endTrip(tripDistance_km);
- setNextTrip();
- prepareNextActivity(timeVariables, chargePointRegistration);
- if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).startTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).startTime_h() ) { // is the next trip also starting this timestep?
- currentTripTimesteps_n = max(1,roundToInt(((tripRecords.get(eventIndex).endTime_h() - tripRecords.get(eventIndex).startTime_h()) / timeParameters.getTimeStep_h())));
- vehicle.startTrip(timeVariables);
- if(vehicle instanceof J_EAEV EV) {
- chargePointRegistration.deregisterChargingRequest(EV);
- }
- }
- }
- }
- }
+ public void manageActivities(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
+ double time_h = timeVariables.getT_h();
+ double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h); // Trip start/end-times are all defined as minutes since monday 00:00h, trips are looped indefinitely
+ if (vehicle.getAvailability()) { // at start of timestep! check for multiple 'events' in timestep!
+ if ( timeSinceWeekStart_h >= tripRecords.get(eventIndex).startTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).startTime_h()) { // is a trip starting this timestep?
+ currentTripTimesteps_n = max(1,roundToInt(((tripRecords.get(eventIndex).endTime_h() - tripRecords.get(eventIndex).startTime_h()) / (timeParameters.getTimeStep_h()))));
+
+ vehicle.startTrip(timeVariables);
+ if(vehicle instanceof J_EAEV EV) {
+ chargePointRegistration.deregisterChargingRequest(EV);
+ }
+ if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).endTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).endTime_h()) { // is the trip also ending this timestep?
+ vehicle.endTrip(tripDistance_km);
+ setNextTrip();
+ prepareNextActivity(timeVariables, chargePointRegistration);
+ }
+ }
+ } else {
+ if (vehicle instanceof J_EAFuelVehicle fuelVehicle) {
+ fuelVehicle.progressTrip(tripDistance_km / currentTripTimesteps_n);
+ }
+ if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).endTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).endTime_h()) { // is a trip ending this timestep?
+ vehicle.endTrip(tripDistance_km);
+ setNextTrip();
+ prepareNextActivity(timeVariables, chargePointRegistration);
+ if (timeSinceWeekStart_h >= tripRecords.get(eventIndex).startTime_h() && (timeSinceWeekStart_h-timeParameters.getTimeStep_h()) < tripRecords.get(eventIndex).startTime_h() ) { // is the next trip also starting this timestep?
+ currentTripTimesteps_n = max(1,roundToInt(((tripRecords.get(eventIndex).endTime_h() - tripRecords.get(eventIndex).startTime_h()) / timeParameters.getTimeStep_h())));
+ vehicle.startTrip(timeVariables);
+ if(vehicle instanceof J_EAEV EV) {
+ chargePointRegistration.deregisterChargingRequest(EV);
+ }
+ }
+ }
+ }
+ }
- /*
- * This method 'Forwards' to the activity at time in timeVariables
- * It also immediately calls prepareNextActivity
- */
- public void setStartIndex(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
- double time_h = timeVariables.getT_h();
- double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h);
- boolean looped = false;
- while ( tripRecords.get(eventIndex).startTime_h() < (timeSinceWeekStart_h ) ) { // If this occurs 'during' a trip, that trip is ignored, it is not executed.
- setNextTrip(); // Skip to the next trip.
-
- if (eventIndex == tripRecords.size()-1 ) {
- if (looped) {
- setNextTrip(); // Increments eventIndex, reverts to first trip of week when 'overflowing'
- break;
- } else {
- looped = true;
- }
- }
- }
- prepareNextActivity(timeVariables, chargePointRegistration);
- }
+ /*
+ * This method 'Forwards' to the activity at time in timeVariables
+ * It also immediately calls prepareNextActivity
+ */
+ public void setStartIndex(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
+ double time_h = timeVariables.getT_h();
+ double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h);
+ boolean looped = false;
+ while ( tripRecords.get(eventIndex).startTime_h() < (timeSinceWeekStart_h ) ) { // If this occurs 'during' a trip, that trip is ignored, it is not executed.
+ setNextTrip(); // Skip to the next trip.
+
+ if (eventIndex == tripRecords.size()-1 ) {
+ if (looped) {
+ setNextTrip(); // Increments eventIndex, reverts to first trip of week when 'overflowing'
+ break;
+ } else {
+ looped = true;
+ }
+ }
+ }
+ prepareNextActivity(timeVariables, chargePointRegistration);
+ }
- /*
- * This method is called after the previous trip ended.
- * It calculates the time to and distance of the coming trip.
- * If the vehicle is an EV it also calculates the charging need, including possible future trips.
- * The function passes this information to the EV and registers the charging request at the chargepoint.
- */
- public void prepareNextActivity(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
- double time_h = timeVariables.getT_h();
-
- // Trip start/end-times are all defined as hours since monday 00:00h
- double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h);
- nextEventStartTime_h = tripRecords.get(eventIndex).startTime_h();
-
- if (eventIndex == 0 && timeSinceWeekStart_h > nextEventStartTime_h) { // Next week's trip!
- nextEventStartTime_h = (nextEventStartTime_h + time_h - timeSinceWeekStart_h) + 168;
- } else {
- nextEventStartTime_h = (nextEventStartTime_h + time_h - timeSinceWeekStart_h);
- }
- idleTimeToNextTrip_h = (nextEventStartTime_h - timeSinceWeekStart_h) % (24*7); // Modulo 24*7 needed because otherwise negative values can occur when trip starts 'next week'.
- tripDistance_km = distanceScaling_fr * tripRecords.get(eventIndex).distance_km(); // Update upcoming trip distance
-
- if (vehicle instanceof J_EAEV ev) {
-
- double energyNeedForNextTrip_kWh = ev.getEnergyConsumption_kWhpkm() * tripDistance_km;
- if (idleTimeToNextTrip_h > 0 && (energyNeedForNextTrip_kWh-ev.getCurrentSOC_kWh())> idleTimeToNextTrip_h * ev.getVehicleChargingCapacity_kW()) {
- traceln("TripTracker reports: charging need for next trip is not feasible! Time till next trip: %s hours, chargeNeed_kWh: %s", roundToDecimal(idleTimeToNextTrip_h,2), roundToDecimal(energyNeedForNextTrip_kWh-ev.getCurrentSOC_kWh(),2));
- }
- // Check if more charging is needed for next trip!
- double nextTripDist_km = 0;
- double nextTripStartTime_h = 0;
-
- if ( eventIndex == tripRecords.size() - 1 ) {
- nextTripDist_km = tripRecords.get(0).distance_km();
- nextTripStartTime_h = tripRecords.get(0).endTime_h();
- } else {
- nextTripDist_km = distanceScaling_fr*tripRecords.get(eventIndex+1).distance_km();
- nextTripStartTime_h = tripRecords.get(eventIndex+1).startTime_h();
- }
- double additionalChargingNeededForNextTrip_kWh = max(0,nextTripDist_km * ev.getEnergyConsumption_kWhpkm() - (nextTripStartTime_h - tripRecords.get(eventIndex).endTime_h())*ev.getVehicleChargingCapacity_kW());
-
- energyNeedForNextTrip_kWh += additionalChargingNeededForNextTrip_kWh;
- energyNeedForNextTrip_kWh = min(energyNeedForNextTrip_kWh+10,ev.getStorageCapacity_kWh());
- ev.setEnergyNeedForNextTrip_kWh(energyNeedForNextTrip_kWh);
-
- //Register EV at the chargepoint
- chargePointRegistration.registerChargingRequest(ev);
- }
- }
-
+ /*
+ * This method is called after the previous trip ended.
+ * It calculates the time to and distance of the coming trip.
+ * If the vehicle is an EV it also calculates the charging need, including possible future trips.
+ * The function passes this information to the EV and registers the charging request at the chargepoint.
+ */
+ public void prepareNextActivity(J_TimeVariables timeVariables, I_ChargePointRegistration chargePointRegistration) {
+ double time_h = timeVariables.getT_h();
+
+ // Trip start/end-times are all defined as hours since monday 00:00h
+ double timeSinceWeekStart_h = getTimeSinceWeekStart_h(time_h);
+ nextEventStartTime_h = tripRecords.get(eventIndex).startTime_h();
+
+ if (eventIndex == 0 && timeSinceWeekStart_h > nextEventStartTime_h) { // Next week's trip!
+ nextEventStartTime_h = (nextEventStartTime_h + time_h - timeSinceWeekStart_h) + 168;
+ } else {
+ nextEventStartTime_h = (nextEventStartTime_h + time_h - timeSinceWeekStart_h);
+ }
+ idleTimeToNextTrip_h = (nextEventStartTime_h - timeSinceWeekStart_h) % (24*7); // Modulo 24*7 needed because otherwise negative values can occur when trip starts 'next week'.
+ tripDistance_km = distanceScaling_fr * tripRecords.get(eventIndex).distance_km(); // Update upcoming trip distance
+
+ if (vehicle instanceof J_EAEV ev) {
+
+ double energyNeedForNextTrip_kWh = ev.getEnergyConsumption_kWhpkm() * tripDistance_km;
+ if (idleTimeToNextTrip_h > 0 && (energyNeedForNextTrip_kWh-ev.getCurrentSOC_kWh())> idleTimeToNextTrip_h * ev.getVehicleChargingCapacity_kW()) {
+ traceln("TripTracker reports: charging need for next trip is not feasible! Time till next trip: %s hours, chargeNeed_kWh: %s", roundToDecimal(idleTimeToNextTrip_h,2), roundToDecimal(energyNeedForNextTrip_kWh-ev.getCurrentSOC_kWh(),2));
+ }
+ // Check if more charging is needed for next trip!
+ double nextTripDist_km = 0;
+ double nextTripStartTime_h = 0;
+
+ if ( eventIndex == tripRecords.size() - 1 ) {
+ nextTripDist_km = tripRecords.get(0).distance_km();
+ nextTripStartTime_h = tripRecords.get(0).endTime_h();
+ } else {
+ nextTripDist_km = distanceScaling_fr*tripRecords.get(eventIndex+1).distance_km();
+ nextTripStartTime_h = tripRecords.get(eventIndex+1).startTime_h();
+ }
+ double additionalChargingNeededForNextTrip_kWh = max(0,nextTripDist_km * ev.getEnergyConsumption_kWhpkm() - (nextTripStartTime_h - tripRecords.get(eventIndex).endTime_h())*ev.getVehicleChargingCapacity_kW());
+
+ energyNeedForNextTrip_kWh += additionalChargingNeededForNextTrip_kWh;
+ energyNeedForNextTrip_kWh = min(energyNeedForNextTrip_kWh+10,ev.getStorageCapacity_kWh());
+ ev.setEnergyNeedForNextTrip_kWh(energyNeedForNextTrip_kWh);
+
+ //Register EV at the chargepoint
+ chargePointRegistration.registerChargingRequest(ev);
+ }
+ }
- //Setters
- public void setVehicle(I_Vehicle vehicle) {
- this.vehicle = vehicle;
- }
- public void setDistanceScaling_fr(double distanceScaling_fr) {
- this.distanceScaling_fr = distanceScaling_fr;
- }
- public void setAnnualDistance_km(double desiredAnnualDistance_km) { // Scale trips to come to a certain total annual distance traveled. This can lead to unfeasibly long trips for EVs!!
- double currentAnnualDistance_km = getAnnualDistance_km();
- double scalingFactor_f = desiredAnnualDistance_km / currentAnnualDistance_km;
-
- ListIterator iterator = tripRecords.listIterator();
- while (iterator.hasNext()) {
+ /*
+ * This method returns a list of trips,
+ * The included trips are those that have a startTime within the range of [startTime_h, endTime_h)
+ * For each of these start times the TripRecord includes the distance for that upcoming trip, which the J_EAEV can translate into required energy.
+ * The times in the TripRecords are 'absolute', i.e. relative to the first of January.
+ */
+ public List getTripsInRange( double startTime_h, double endTime_h ) {
+ List trips = new ArrayList<>();
+ if (endTime_h < startTime_h) {
+ // Could return an empty list instead, but prefer to throw an exception to hint at something going wrong.
+ throw new RuntimeException(String.format("Could not get trips in range [ %s, %s ), since startTime is after endTime_h", startTime_h, endTime_h));
+ }
+ int startWeek = this.timeParameters.getWeekIndex(startTime_h);
+ int endWeek = this.timeParameters.getWeekIndex(endTime_h);
+ for (int week = startWeek; week <= endWeek; week++) {
+ double weekStartTime_h = this.timeParameters.getWeekStart_h(week);
+ for (TripRecord trip : tripRecords) {
+ double absStart = weekStartTime_h + trip.startTime_h();
+ double absEnd = weekStartTime_h + trip.endTime_h();
+ if (absStart >= startTime_h && absStart < endTime_h) {
+ trips.add(new TripRecord(absStart, absEnd, trip.distance_km()));
+ }
+ }
+ }
+ return trips;
+ }
+
+ //Setters
+ public void setVehicle(I_Vehicle vehicle) {
+ this.vehicle = vehicle;
+ }
+ public void setDistanceScaling_fr(double distanceScaling_fr) {
+ this.distanceScaling_fr = distanceScaling_fr;
+ }
+ public void setAnnualDistance_km(double desiredAnnualDistance_km) { // Scale trips to come to a certain total annual distance traveled. This can lead to unfeasibly long trips for EVs!!
+ double currentAnnualDistance_km = getAnnualDistance_km();
+ double scalingFactor_f = desiredAnnualDistance_km / currentAnnualDistance_km;
+
+ ListIterator iterator = tripRecords.listIterator();
+ while (iterator.hasNext()) {
TripRecord record = iterator.next();
iterator.set(new TripRecord(
record.startTime_h(),
@@ -222,48 +244,52 @@ public void setAnnualDistance_km(double desiredAnnualDistance_km) { // Scale tri
record.distance_km() * scalingFactor_f
));
}
- }
- //Getters
- public I_Vehicle getVehicle() {
- return this.vehicle;
- }
- public double getNextEventStartTime_h() {
- return nextEventStartTime_h;
- }
-
- public double getDistanceScaling_fr( ) {
- return this.distanceScaling_fr;
- }
- public double getAnnualDistance_km() {
- double currentAnnualDistance_km = 52 * tripRecords.stream().mapToDouble(TripRecord::distance_km).sum(); // assumed trip-data is one week long!! Hence the 52, for 52 weeks in a year.
- return currentAnnualDistance_km;
- }
-
- public static record TripRecord(double startTime_h, double endTime_h, double distance_km) {
- }
-
- @Override
- public void storeStatesAndReset() {
- eventIndexStored = eventIndex;
- nextEventStartTimeStored_h = nextEventStartTime_h;
- idleTimeToNextTripStored_h = idleTimeToNextTrip_h;
- idleTimeToNextTrip_h = 0;
- // Don't forget to call setStartIndex !
- }
-
- @Override
- public void restoreStates() {
- eventIndex = eventIndexStored;
- nextEventStartTime_h = nextEventStartTimeStored_h;
- idleTimeToNextTrip_h = idleTimeToNextTripStored_h;
- tripDistance_km = distanceScaling_fr * tripRecords.get(eventIndex).distance_km(); // Update upcoming trip distance
- }
-
- @Override
- public String toString() {
- String outputString = "J_ActivityTrackerTrips: \n";
- outputString += "Based on " + (CSVRowIndex != null ? "CSV data with row index: " + CSVRowIndex : "Custom input") + "\n";
- outputString += "Distance Scaling = " + this.distanceScaling_fr + " ";
- return outputString;
- }
+ }
+ //Getters
+ public I_Vehicle getVehicle() {
+ return this.vehicle;
+ }
+ public double getNextEventStartTime_h() {
+ return nextEventStartTime_h;
+ }
+
+ public double getCurrentTripEndTime_h() {
+ return this.tripRecords.get(eventIndex).endTime_h();
+ }
+
+ public double getDistanceScaling_fr( ) {
+ return this.distanceScaling_fr;
+ }
+ public double getAnnualDistance_km() {
+ double currentAnnualDistance_km = 52 * tripRecords.stream().mapToDouble(TripRecord::distance_km).sum(); // assumed trip-data is one week long!! Hence the 52, for 52 weeks in a year.
+ return currentAnnualDistance_km;
+ }
+
+ public static record TripRecord(double startTime_h, double endTime_h, double distance_km) {}
+
+
+ @Override
+ public void storeStatesAndReset() {
+ eventIndexStored = eventIndex;
+ nextEventStartTimeStored_h = nextEventStartTime_h;
+ idleTimeToNextTripStored_h = idleTimeToNextTrip_h;
+ idleTimeToNextTrip_h = 0;
+ // Don't forget to call setStartIndex !
+ }
+
+ @Override
+ public void restoreStates() {
+ eventIndex = eventIndexStored;
+ nextEventStartTime_h = nextEventStartTimeStored_h;
+ idleTimeToNextTrip_h = idleTimeToNextTripStored_h;
+ tripDistance_km = distanceScaling_fr * tripRecords.get(eventIndex).distance_km(); // Update upcoming trip distance
+ }
+
+ @Override
+ public String toString() {
+ String outputString = "J_ActivityTrackerTrips: \n";
+ outputString += "Based on " + (CSVRowIndex != null ? "CSV data with row index: " + CSVRowIndex : "Custom input") + "\n";
+ outputString += "Distance Scaling = " + this.distanceScaling_fr + " ";
+ return outputString;
+ }
}
\ No newline at end of file
diff --git a/_alp/Classes/Class.J_AssetTypeForecast.java b/_alp/Classes/Class.J_AssetTypeForecast.java
new file mode 100644
index 00000000..cfec47ea
--- /dev/null
+++ b/_alp/Classes/Class.J_AssetTypeForecast.java
@@ -0,0 +1,9 @@
+/**
+ * J_AssetTypeForecast
+ */
+public record J_AssetTypeForecast(
+ Class extends I_AssetManagement> assetType,
+ Map load_kW,
+ OL_ForecastStatus status,
+ String reason // Optional field to give an explanation for the status
+) {}
\ No newline at end of file
diff --git a/_alp/Classes/Class.J_BackupGeneratorManagementContractCapacity.java b/_alp/Classes/Class.J_BackupGeneratorManagementContractCapacity.java
index d8b52757..19e7eb7c 100644
--- a/_alp/Classes/Class.J_BackupGeneratorManagementContractCapacity.java
+++ b/_alp/Classes/Class.J_BackupGeneratorManagementContractCapacity.java
@@ -37,6 +37,13 @@ public void manageBackupGenerator(J_TimeVariables timeVariables) {
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BackupGeneratorManagement.class, loadMap, status, reason);
+ }
+
////Store and reset states
public void storeStatesAndReset() {
//Nothing to store and reset
diff --git a/_alp/Classes/Class.J_BackupGeneratorManagementExternalSetpoint.java b/_alp/Classes/Class.J_BackupGeneratorManagementExternalSetpoint.java
index d6da0e81..55dd94a6 100644
--- a/_alp/Classes/Class.J_BackupGeneratorManagementExternalSetpoint.java
+++ b/_alp/Classes/Class.J_BackupGeneratorManagementExternalSetpoint.java
@@ -41,6 +41,13 @@ public void setBackupGeneratorSetpoint_kW(double backupGeneratorPowerSetpoint_kW
this.backupGeneratorPowerSetpoint_kW = backupGeneratorPowerSetpoint_kW;
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "External Setpoint Management can not be forecasted.";
+ return new J_AssetTypeForecast(I_BackupGeneratorManagement.class, loadMap, status, reason);
+ }
+
////Store and reset states
public void storeStatesAndReset() {
//Nothing to store and reset
diff --git a/_alp/Classes/Class.J_BatteryManagementExternalSetpoint.java b/_alp/Classes/Class.J_BatteryManagementExternalSetpoint.java
index e448015b..11cb5b7a 100644
--- a/_alp/Classes/Class.J_BatteryManagementExternalSetpoint.java
+++ b/_alp/Classes/Class.J_BatteryManagementExternalSetpoint.java
@@ -53,7 +53,12 @@ public void manageBattery(J_TimeVariables timeVariables) {
}
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "External Setpoint Management can not be forecasted.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementLocalBalancing.java b/_alp/Classes/Class.J_BatteryManagementLocalBalancing.java
index 4c294c8d..dbdf9cf5 100644
--- a/_alp/Classes/Class.J_BatteryManagementLocalBalancing.java
+++ b/_alp/Classes/Class.J_BatteryManagementLocalBalancing.java
@@ -70,6 +70,13 @@ public void manageBattery(J_TimeVariables timeVariables) {
gc.f_updateFlexAssetFlows(gc.p_batteryAsset, chargeSetpoint_kW / gc.p_batteryAsset.getCapacityElectric_kW(), timeVariables);
}
}
+
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
private double getDeliveryCapacity_kW() {
return gc.v_liveConnectionMetaData.getContractedDeliveryCapacity_kW();
diff --git a/_alp/Classes/Class.J_BatteryManagementOff.java b/_alp/Classes/Class.J_BatteryManagementOff.java
index 564475dc..aca2aaa3 100644
--- a/_alp/Classes/Class.J_BatteryManagementOff.java
+++ b/_alp/Classes/Class.J_BatteryManagementOff.java
@@ -36,9 +36,15 @@ public void manageBattery(J_TimeVariables timeVariables) {
}
}
-
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] electricityLoad_kW = new Double[timeStepsInForecast];
+ Arrays.fill(electricityLoad_kW, 0.0);
+ Map loadMap = new HashMap<>();
+ loadMap.put(OL_EnergyCarriers.ELECTRICITY, electricityLoad_kW);
+ OL_ForecastStatus status = OL_ForecastStatus.PERFECT_FORECAST;
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, null);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementPeakShaving.java b/_alp/Classes/Class.J_BatteryManagementPeakShaving.java
index 2dc10a0e..7d776bac 100644
--- a/_alp/Classes/Class.J_BatteryManagementPeakShaving.java
+++ b/_alp/Classes/Class.J_BatteryManagementPeakShaving.java
@@ -149,8 +149,12 @@ private double getBalanceElectricity_kW() {
}
}
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementPeakShavingForecast.java b/_alp/Classes/Class.J_BatteryManagementPeakShavingForecast.java
index 0024a11d..2550e0a3 100644
--- a/_alp/Classes/Class.J_BatteryManagementPeakShavingForecast.java
+++ b/_alp/Classes/Class.J_BatteryManagementPeakShavingForecast.java
@@ -198,7 +198,12 @@ else if (agent instanceof EnergyCoop) {
this.initializeAssets();
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementPrice.java b/_alp/Classes/Class.J_BatteryManagementPrice.java
index 1f334367..8d212f01 100644
--- a/_alp/Classes/Class.J_BatteryManagementPrice.java
+++ b/_alp/Classes/Class.J_BatteryManagementPrice.java
@@ -90,8 +90,12 @@ else if (WTP_discharge_eurpkWh < currentElectricityPriceCharge_eurpkWh) {
}
}
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementProfile.java b/_alp/Classes/Class.J_BatteryManagementProfile.java
index 33d4d60d..c34a378b 100644
--- a/_alp/Classes/Class.J_BatteryManagementProfile.java
+++ b/_alp/Classes/Class.J_BatteryManagementProfile.java
@@ -61,6 +61,13 @@ public void setProfilePointer(J_ProfilePointer batteryProfilePointer_kW) {
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
+
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_BatteryManagementSelfConsumption.java b/_alp/Classes/Class.J_BatteryManagementSelfConsumption.java
index bf5380c1..135b8bcc 100644
--- a/_alp/Classes/Class.J_BatteryManagementSelfConsumption.java
+++ b/_alp/Classes/Class.J_BatteryManagementSelfConsumption.java
@@ -42,8 +42,12 @@ public void manageBattery(J_TimeVariables timeVariables) {
}
}
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_BatteryManagementSelfConsumptionGridNode.java b/_alp/Classes/Class.J_BatteryManagementSelfConsumptionGridNode.java
index 0f65273c..d9fb0d99 100644
--- a/_alp/Classes/Class.J_BatteryManagementSelfConsumptionGridNode.java
+++ b/_alp/Classes/Class.J_BatteryManagementSelfConsumptionGridNode.java
@@ -45,7 +45,12 @@ public void manageBattery(J_TimeVariables timeVariables) {
}
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_BatteryManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_ChargingManagementExternalSetpoint.java b/_alp/Classes/Class.J_ChargingManagementExternalSetpoint.java
index d7fc1c9f..020c7019 100644
--- a/_alp/Classes/Class.J_ChargingManagementExternalSetpoint.java
+++ b/_alp/Classes/Class.J_ChargingManagementExternalSetpoint.java
@@ -56,6 +56,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
map_chargingSetpoints_kW = new HashMap<>();
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "External Setpoint Management can not be forecasted.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setChargingSetpoints(Map map_chargingSetpoints_kW) {
this.map_chargingSetpoints_kW = map_chargingSetpoints_kW;
}
diff --git a/_alp/Classes/Class.J_ChargingManagementGridBalancing.java b/_alp/Classes/Class.J_ChargingManagementGridBalancing.java
index 5623762f..b3cfe419 100644
--- a/_alp/Classes/Class.J_ChargingManagementGridBalancing.java
+++ b/_alp/Classes/Class.J_ChargingManagementGridBalancing.java
@@ -75,6 +75,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setV2GActive(boolean activateV2G) {
this.V2GActive = activateV2G;
this.gc.c_electricVehicles.forEach(ev -> ev.setV2GActive(activateV2G)); // NEEDED TO HAVE EV ASSET IN CORRECT assetFlowCatagory
diff --git a/_alp/Classes/Class.J_ChargingManagementLocalBalancing.java b/_alp/Classes/Class.J_ChargingManagementLocalBalancing.java
index 8108f93c..212e80df 100644
--- a/_alp/Classes/Class.J_ChargingManagementLocalBalancing.java
+++ b/_alp/Classes/Class.J_ChargingManagementLocalBalancing.java
@@ -73,6 +73,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setV2GActive(boolean activateV2G) {
this.V2GActive = activateV2G;
this.gc.c_electricVehicles.forEach(ev -> ev.setV2GActive(activateV2G)); // NEEDED TO HAVE EV ASSET IN CORRECT assetFlowCatagory
diff --git a/_alp/Classes/Class.J_ChargingManagementMaxAvailablePower.java b/_alp/Classes/Class.J_ChargingManagementMaxAvailablePower.java
index 430fc8c9..9b5f39b5 100644
--- a/_alp/Classes/Class.J_ChargingManagementMaxAvailablePower.java
+++ b/_alp/Classes/Class.J_ChargingManagementMaxAvailablePower.java
@@ -69,6 +69,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setV2GActive(boolean activateV2G) {
this.V2GActive = activateV2G;
this.gc.c_electricVehicles.forEach(ev -> ev.setV2GActive(activateV2G)); // NEEDED TO HAVE EV ASSET IN CORRECT assetFlowCatagory
@@ -79,9 +86,6 @@ public boolean getV2GActive() {
return this.V2GActive;
}
-
-
-
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_ChargingManagementOffPeak.java b/_alp/Classes/Class.J_ChargingManagementOffPeak.java
index 83b9bd0f..c3e08d0d 100644
--- a/_alp/Classes/Class.J_ChargingManagementOffPeak.java
+++ b/_alp/Classes/Class.J_ChargingManagementOffPeak.java
@@ -89,6 +89,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setStartTimeOfReducedChargingInterval_hr(double startTimeOfReducedChargingInterval_hr) {
this.startTimeOfReducedChargingInterval_hr = startTimeOfReducedChargingInterval_hr;
}
diff --git a/_alp/Classes/Class.J_ChargingManagementPrice.java b/_alp/Classes/Class.J_ChargingManagementPrice.java
index ca71e7f6..01a2aee8 100644
--- a/_alp/Classes/Class.J_ChargingManagementPrice.java
+++ b/_alp/Classes/Class.J_ChargingManagementPrice.java
@@ -70,6 +70,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setV2GActive(boolean activateV2G) {
this.V2GActive = activateV2G;
this.gc.c_electricVehicles.forEach(ev -> ev.setV2GActive(activateV2G)); // NEEDED TO HAVE EV ASSET IN CORRECT assetFlowCatagory
diff --git a/_alp/Classes/Class.J_ChargingManagementPriceScheduled.java b/_alp/Classes/Class.J_ChargingManagementPriceScheduled.java
index 9a3b97aa..97bb16f2 100644
--- a/_alp/Classes/Class.J_ChargingManagementPriceScheduled.java
+++ b/_alp/Classes/Class.J_ChargingManagementPriceScheduled.java
@@ -150,6 +150,13 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
activeSessions.removeIf(session -> session.isFinished); // Must be outside of for-loop over this collection!
}
+
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
public void abortSession(I_ChargingRequest chargingRequest) {
previousChargingRequests.remove(chargingRequest);
diff --git a/_alp/Classes/Class.J_ChargingManagementSimple.java b/_alp/Classes/Class.J_ChargingManagementSimple.java
index 8be8fa2f..b3d483ae 100644
--- a/_alp/Classes/Class.J_ChargingManagementSimple.java
+++ b/_alp/Classes/Class.J_ChargingManagementSimple.java
@@ -4,6 +4,9 @@
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+
+import zero_engine.J_ActivityTrackerTrips.TripRecord;
+
import java.util.EnumSet;
@JsonAutoDetect(
@@ -51,6 +54,77 @@ public void manageCharging(J_ChargePoint chargePoint, J_TimeVariables timeVariab
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ // TODO: Check if this works for (public) charging sessions aswell
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] electricityLoad_kW = new Double[timeStepsInForecast];
+ Arrays.fill(electricityLoad_kW, 0.0);
+
+ for (J_EAEV ev : this.gc.c_electricVehicles) {
+ double[] EVLoad_kW = new double[timeStepsInForecast];
+ J_ActivityTrackerTrips tripTracker = ev.getTripTracker();
+ List trips = tripTracker.getTripsInRange(timeOfIntervalStart_h, timeOfIntervalEnd_h);
+
+ double maximalStorageCapacity_kWh = ev.getStorageCapacity_kWh();
+ double currentSOC_kWh = ev.getCurrentSOC_kWh(); // Assumes the SOC of the EV at start of forecast is current SOC
+ double work_kWh = maximalStorageCapacity_kWh - currentSOC_kWh;
+ double endTimeLastTrip_h = ev.getAvailability() ? timeOfIntervalStart_h : tripTracker.getCurrentTripEndTime_h()%24; // Assumes the current trip ends today, i.e. no trips > 24 hours exist)
+ double firstAvailableChargingTime_h = this.timeParameters.getTimeStep_h() * Math.ceil(endTimeLastTrip_h / this.timeParameters.getTimeStep_h());
+ double startTimeNextTrip_h = trips.size() > 0 ? trips.get(0).startTime_h() : timeOfIntervalEnd_h;
+ double lastAvailableChargingTime_h = this.timeParameters.getTimeStep_h() * Math.floor(startTimeNextTrip_h / this.timeParameters.getTimeStep_h());
+ double maxPower_kW = ev.getVehicleChargingCapacity_kW();
+ double maxWork_kWh = (lastAvailableChargingTime_h - firstAvailableChargingTime_h + this.timeParameters.getTimeStep_h()) * maxPower_kW;
+ double initialWork_kWh = max(0, min(work_kWh, maxWork_kWh));
+ double remainingWork_kWh = initialWork_kWh;
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i*this.timeParameters.getTimeStep_h();
+ if (t >= firstAvailableChargingTime_h && t <= lastAvailableChargingTime_h) {
+ EVLoad_kW[i] = max(0, min(maxPower_kW, remainingWork_kWh / this.timeParameters.getTimeStep_h()));
+ remainingWork_kWh -= EVLoad_kW[i] * this.timeParameters.getTimeStep_h();
+ if (DoubleCompare.equalsZero(remainingWork_kWh) || DoubleCompare.lessThanZero(remainingWork_kWh)) {
+ break;
+ }
+ }
+ }
+ currentSOC_kWh += initialWork_kWh - remainingWork_kWh;
+
+ for (int tripIndex = 0; tripIndex < trips.size(); tripIndex++) {
+ TripRecord trip = trips.get(tripIndex);
+ double distance_km = trip.distance_km();
+ currentSOC_kWh -= distance_km * ev.getEnergyConsumption_kWhpkm();
+ work_kWh = maximalStorageCapacity_kWh - currentSOC_kWh;
+ endTimeLastTrip_h = trip.endTime_h();
+ firstAvailableChargingTime_h = this.timeParameters.getTimeStep_h() * Math.ceil(endTimeLastTrip_h / this.timeParameters.getTimeStep_h());
+ startTimeNextTrip_h = (tripIndex == trips.size() - 1) ? timeOfIntervalEnd_h : trips.get(tripIndex+1).startTime_h();
+ lastAvailableChargingTime_h = this.timeParameters.getTimeStep_h() * Math.floor(startTimeNextTrip_h / this.timeParameters.getTimeStep_h());
+ maxWork_kWh = (lastAvailableChargingTime_h - firstAvailableChargingTime_h + this.timeParameters.getTimeStep_h()) * maxPower_kW;
+ initialWork_kWh = max(0, min(work_kWh, maxWork_kWh));
+ remainingWork_kWh = initialWork_kWh;
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i*this.timeParameters.getTimeStep_h();
+ if (t >= firstAvailableChargingTime_h && t <= lastAvailableChargingTime_h) {
+ EVLoad_kW[i] = max(0, min(maxPower_kW, remainingWork_kWh / this.timeParameters.getTimeStep_h()));
+ double x = max(0, min(maxPower_kW, remainingWork_kWh / this.timeParameters.getTimeStep_h()));
+ remainingWork_kWh -= EVLoad_kW[i] * this.timeParameters.getTimeStep_h();
+ if (DoubleCompare.equalsZero(remainingWork_kWh) || DoubleCompare.lessThanZero(remainingWork_kWh)) {
+ break;
+ }
+ }
+ }
+ currentSOC_kWh += initialWork_kWh - remainingWork_kWh;
+ }
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ electricityLoad_kW[i] += EVLoad_kW[i];
+ }
+ }
+
+ OL_ForecastStatus status = OL_ForecastStatus.ESTIMATED_FORECAST;
+ Map loadMap = new HashMap<>();
+ loadMap.put(OL_EnergyCarriers.ELECTRICITY, electricityLoad_kW);
+ String reason = "Forecast is not perfect as EV starting SOC is guessed. If forecast starttime is the current modeltime forecast is perfect.";
+ return new J_AssetTypeForecast(I_ChargingManagement.class, loadMap, status, reason);
+ }
+
public void setV2GActive(boolean activateV2G) {
if(activateV2G) {
throw new RuntimeException("Trying to Activate V2G for chargingManagement Simple -> Not supported");
@@ -61,7 +135,6 @@ public boolean getV2GActive() {
return this.V2GActive;
}
-
//Get parentagent
public Agent getParentAgent() {
return this.gc;
@@ -75,10 +148,8 @@ public void restoreStates() {
}
-
@Override
public String toString() {
return "Active charging type: " + this.activeChargingType;
-
}
}
\ No newline at end of file
diff --git a/_alp/Classes/Class.J_CurtailManagementContractCapacity.java b/_alp/Classes/Class.J_CurtailManagementContractCapacity.java
index c425246f..105457fa 100644
--- a/_alp/Classes/Class.J_CurtailManagementContractCapacity.java
+++ b/_alp/Classes/Class.J_CurtailManagementContractCapacity.java
@@ -45,6 +45,13 @@ public void manageCurtailment(J_TimeVariables timeVariables) {
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_CurtailManagement.class, loadMap, status, reason);
+ }
+
////Store and reset states
public void storeStatesAndReset() {
//Nothing to store and reset
diff --git a/_alp/Classes/Class.J_CurtailManagementExternalSetpoint.java b/_alp/Classes/Class.J_CurtailManagementExternalSetpoint.java
index be9a3324..2a6e4a90 100644
--- a/_alp/Classes/Class.J_CurtailManagementExternalSetpoint.java
+++ b/_alp/Classes/Class.J_CurtailManagementExternalSetpoint.java
@@ -53,6 +53,13 @@ public void manageCurtailment(J_TimeVariables timeVariables) {
curtailmentSetpoint_kW = 0;
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "External Setpoint Management can not be forecasted.";
+ return new J_AssetTypeForecast(I_CurtailManagement.class, loadMap, status, reason);
+ }
+
public void setCurtailmentSetpoint(double curtailmentSetpoint_kW) {
this.curtailmentSetpoint_kW = curtailmentSetpoint_kW;
}
diff --git a/_alp/Classes/Class.J_CurtailManagementPrice.java b/_alp/Classes/Class.J_CurtailManagementPrice.java
index e54f8b0d..9f2bdae3 100644
--- a/_alp/Classes/Class.J_CurtailManagementPrice.java
+++ b/_alp/Classes/Class.J_CurtailManagementPrice.java
@@ -46,6 +46,13 @@ public void manageCurtailment(J_TimeVariables timeVariables) {
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_CurtailManagement.class, loadMap, status, reason);
+ }
+
////Store and reset states
public void storeStatesAndReset() {
//Nothing to store and reset
diff --git a/_alp/Classes/Class.J_EAConversionHeatPump.java b/_alp/Classes/Class.J_EAConversionHeatPump.java
index b5ce9646..f2f3b6d1 100644
--- a/_alp/Classes/Class.J_EAConversionHeatPump.java
+++ b/_alp/Classes/Class.J_EAConversionHeatPump.java
@@ -131,7 +131,7 @@ public OL_AmbientTempType getAmbientTempType() {
public double calculateCOP(double outputTemperature_degC, double baseTemperature_degC) {
//double COP_r = this.eta_r * ( 273.15 + this.outputTemperature_degC ) / ( this.outputTemperature_degC - this.baseTemperature_degC );
- double deltaT = max(1,this.outputTemperature_degC - this.baseTemperature_degC); // Limit deltaT to at least 1 degree.
+ double deltaT = max(1, outputTemperature_degC - baseTemperature_degC); // Limit deltaT to at least 1 degree.
double COP_r = 8.74 - 0.190 * deltaT + 0.00126 * deltaT*deltaT;
return COP_r;
}
diff --git a/_alp/Classes/Class.J_ElectrolyserManagementPowerSurplus.java b/_alp/Classes/Class.J_ElectrolyserManagementPowerSurplus.java
index cb6fe5d9..1f4da9c0 100644
--- a/_alp/Classes/Class.J_ElectrolyserManagementPowerSurplus.java
+++ b/_alp/Classes/Class.J_ElectrolyserManagementPowerSurplus.java
@@ -193,6 +193,13 @@ else if(timeVariables.getTimeStepsElapsed() < (8760-forecast_time_h)/timeParamet
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ElectrolyserManagement.class, loadMap, status, reason);
+ }
+
public void setTarget(Agent target) {
this.target = target;
}
diff --git a/_alp/Classes/Class.J_ElectrolyserManagementPrice.java b/_alp/Classes/Class.J_ElectrolyserManagementPrice.java
index 0815e466..17f45f74 100644
--- a/_alp/Classes/Class.J_ElectrolyserManagementPrice.java
+++ b/_alp/Classes/Class.J_ElectrolyserManagementPrice.java
@@ -141,6 +141,13 @@ private void f_electrolyserStateControl_Price(J_EAConversionElectrolyser electro
}
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_ElectrolyserManagement.class, loadMap, status, reason);
+ }
+
public void setElectricityPriceMaxForProfit_eurpkWh(double electricityPriceMaxForProfit_eurpkWh) {
this.electricityPriceMaxForProfit_eurpkWh = electricityPriceMaxForProfit_eurpkWh;
}
diff --git a/_alp/Classes/Class.J_FlexProfileManagementDefault.java b/_alp/Classes/Class.J_FlexProfileManagementDefault.java
index 88cdf05e..fc6e6dbe 100644
--- a/_alp/Classes/Class.J_FlexProfileManagementDefault.java
+++ b/_alp/Classes/Class.J_FlexProfileManagementDefault.java
@@ -22,6 +22,26 @@ public void manageFlexProfiles(J_TimeVariables timeVariables) {
gc.c_flexProfileAssets.forEach(flexProfile -> gc.f_updateFlexAssetFlows(flexProfile, 1.0, timeVariables));
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Map loadMap = new HashMap<>();
+ for (J_EAFlexProfile flexProfile : gc.c_flexProfileAssets) {
+ OL_EnergyCarriers EC = flexProfile.getEnergyCarrier();
+ if (loadMap.get(EC) == null) {
+ Double[] loadProfile_kW = new Double[timeStepsInForecast];
+ Arrays.fill(loadProfile_kW, 0.0);
+ loadMap.put(EC, loadProfile_kW);
+ }
+ J_ProfilePointer pp = flexProfile.getProfilePointer();
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * this.timeParameters.getTimeStep_h();
+ loadMap.get(EC)[i] += pp.getValue(t);
+ }
+ }
+ OL_ForecastStatus status = OL_ForecastStatus.PERFECT_FORECAST;
+ return new J_AssetTypeForecast(I_FlexProfileManagement.class, loadMap, status, null);
+ }
+
////Store and reset states
public void storeStatesAndReset() {
//Nothing to store and reset
diff --git a/_alp/Classes/Class.J_FlexProfileManagementHeatprofileHeatpump.java b/_alp/Classes/Class.J_FlexProfileManagementHeatprofileHeatpump.java
index b4738f86..117fb42b 100644
--- a/_alp/Classes/Class.J_FlexProfileManagementHeatprofileHeatpump.java
+++ b/_alp/Classes/Class.J_FlexProfileManagementHeatprofileHeatpump.java
@@ -141,6 +141,13 @@ private void createNewFlexProfileSetpointArray(J_TimeVariables timeVariables) {
this.flexProfileSetpointArray_fr = newFlexProfileSetpointArray;
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_FlexProfileManagement.class, loadMap, status, reason);
+ }
+
//Setters
public void setMaxFlexProfileShift_fr(double maxFlexProfileShift_fr) {
if(maxFlexProfileShift_fr<0) {
diff --git a/_alp/Classes/Class.J_HeatingManagementCHP.java b/_alp/Classes/Class.J_HeatingManagementCHP.java
index 7493105a..5496331b 100644
--- a/_alp/Classes/Class.J_HeatingManagementCHP.java
+++ b/_alp/Classes/Class.J_HeatingManagementCHP.java
@@ -95,7 +95,12 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_HeatingManagementDistrictHeating.java b/_alp/Classes/Class.J_HeatingManagementDistrictHeating.java
index 34eb0e5c..ecb21687 100644
--- a/_alp/Classes/Class.J_HeatingManagementDistrictHeating.java
+++ b/_alp/Classes/Class.J_HeatingManagementDistrictHeating.java
@@ -120,7 +120,13 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_HeatingManagementGhost.java b/_alp/Classes/Class.J_HeatingManagementGhost.java
index d6ee563f..58f5443f 100644
--- a/_alp/Classes/Class.J_HeatingManagementGhost.java
+++ b/_alp/Classes/Class.J_HeatingManagementGhost.java
@@ -72,8 +72,12 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java b/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java
index 30d46a77..856c21ae 100644
--- a/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java
+++ b/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java
@@ -351,7 +351,12 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
diff --git a/_alp/Classes/Class.J_HeatingManagementNeighborhood.java b/_alp/Classes/Class.J_HeatingManagementNeighborhood.java
index 93b50c8a..f6d75394 100644
--- a/_alp/Classes/Class.J_HeatingManagementNeighborhood.java
+++ b/_alp/Classes/Class.J_HeatingManagementNeighborhood.java
@@ -322,7 +322,13 @@ public I_ProfileAsset getHeatDemandProfile(String name) {
return heatDemandProfiles.get(name);
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ OL_ForecastStatus status = OL_ForecastStatus.NOT_FORECASTABLE;
+ String reason = "Not yet implemented.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_HeatingManagementPIcontrol.java b/_alp/Classes/Class.J_HeatingManagementPIcontrol.java
index 3fad5889..e9fc88af 100644
--- a/_alp/Classes/Class.J_HeatingManagementPIcontrol.java
+++ b/_alp/Classes/Class.J_HeatingManagementPIcontrol.java
@@ -237,6 +237,133 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] loadProfile_kW = new Double[timeStepsInForecast];
+ J_ProfilePointer ambientTemperatureProfile = this.gc.energyModel.pp_ambientTemperature_degC;
+ J_ProfileForecaster ambientTempeartureForecast = this.gc.energyModel.pf_ambientTemperature_degC;
+ double[] buildingHeatDemand_kW = this.getBuildingHeatDemandProfile(timeOfIntervalStart_h, timeStepsInForecast, ambientTemperatureProfile, ambientTempeartureForecast);
+ double[] otherFixedHeatDemand_kW = this.gc.f_getFixedAssetForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h, OL_EnergyCarriers.HEAT, this.timeParameters);
+
+ // We switch over the heating type twice, first to set the EnergyCarrier
+ OL_EnergyCarriers EC;
+ switch (this.gc.f_getCurrentHeatingType()) {
+ case GAS_BURNER:
+ EC = OL_EnergyCarriers.METHANE;
+ break;
+ case HYDROGENBURNER:
+ EC = OL_EnergyCarriers.HYDROGEN;
+ break;
+ case LT_DISTRICTHEAT:
+ case ELECTRIC_HEATPUMP:
+ EC = OL_EnergyCarriers.ELECTRICITY;
+ break;
+ case DISTRICTHEAT:
+ Double[] heatLoad = Arrays.stream(buildingHeatDemand_kW).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+ return new J_AssetTypeForecast(J_HeatingManagementPIcontrol.class, loadMap, OL_ForecastStatus.ESTIMATED_FORECAST, "GC connected to districtheating, so all heat demand is import. Building forecast simplified by omitting solar radiation & ventilation.");
+ default:
+ throw new RuntimeException(String.format("Tried to forecast J_HeatingManagementPIControl, but encountered an unexepected heating type %s in GC %s", this.gc.f_getCurrentHeatingType(), this.gc.p_gridConnectionID));
+ }
+
+ // Then to determine the profile.
+ // Here we make a distinction between fixed efficiency, and efficiency variable per timestep.
+ boolean fixedEfficiency = false;
+ double fixedEfficiency_fr = 1.0;
+ J_EAConversionHeatPump hp = null;
+ switch (this.gc.f_getCurrentHeatingType()) {
+ case LT_DISTRICTHEAT:
+ fixedEfficiency = true;
+ hp = ((J_EAConversionHeatPump)this.heatingAsset);
+ fixedEfficiency_fr = hp.getCOP();
+ break;
+ case GAS_BURNER:
+ case HYDROGENBURNER:
+ fixedEfficiency = true;
+ fixedEfficiency_fr = this.heatingAsset.getEta_r();
+ break;
+ case ELECTRIC_HEATPUMP:
+ hp = ((J_EAConversionHeatPump)this.heatingAsset);
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double heatDemand_kW = buildingHeatDemand_kW[i] + otherFixedHeatDemand_kW[i];
+ double efficiency_fr = hp.calculateCOP(hp.getOutputTemperature_degC(), ambientTemperatureProfile.getValue(t));
+ double load_kW = heatDemand_kW / efficiency_fr;
+ loadProfile_kW[i] = load_kW;
+ }
+ break;
+ }
+
+ if (fixedEfficiency) {
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double heatDemand_kW = buildingHeatDemand_kW[i] + otherFixedHeatDemand_kW[i];
+ double load_kW = heatDemand_kW / fixedEfficiency_fr;
+ loadProfile_kW[i] = load_kW;
+ }
+ }
+ loadMap.put(EC, loadProfile_kW);
+ // Building is a flex asset so its heat demand is included in system bounds of heating management, but fixed profiles are not.
+ Double[] heatLoad = Arrays.stream(otherFixedHeatDemand_kW).map(d -> -d).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+ OL_ForecastStatus status = OL_ForecastStatus.ESTIMATED_FORECAST;
+ String reason = "PI & Building states based on current timestep. Building forecast simplified by omitting solar radiation & ventilation.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+
+ private double[] getBuildingHeatDemandProfile(double timeAtStartForecast_h, int timeStepsInForecast, J_ProfilePointer ambientTemperatureProfile, J_ProfileForecaster ambientTempeartureForecast) {
+ double[] buildingHeatDemandProfile_kW = new double[timeStepsInForecast];
+
+ double dayStartTime_h = this.heatingPreferences.getStartOfDayTime_h();
+ double nightStartTime_h = this.heatingPreferences.getStartOfNightTime_h();
+ double daySetpoint_degC = this.heatingPreferences.getDayTimeSetPoint_degC();
+ double nightSetpoint_degC = this.heatingPreferences.getNightTimeSetPoint_degC();
+ double avgTemp24h_degC = ambientTempeartureForecast.getForecast(); // Assumes timeAtStartForecast_h is current model time and forecasting horizon is 24h.
+
+ double simBuildingTemp_degC = this.building.getCurrentTemperature();
+ double simFilteredSetpoint_degC = this.filteredCurrentSetpoint_degC;
+ double simIState_hDegC = this.I_state_hDegC;
+
+ double pGain_kWpDegC = this.P_gain_kWpDegC;
+ double iGain_kWphDegC = this.I_gain_kWphDegC;
+ double filterTimeScale_h = this.setpointFilterTimeScale_h;
+ double timeStep_h = this.timeParameters.getTimeStep_h();
+
+ double lossFactor_WpK = this.building.getLossFactor_WpK();
+ double lossScalingFactor_fr = this.building.getLossScalingFactor_fr();
+ double heatCapacity_kWhpK = this.building.getHeatCapacity_JpK() / 3.6e6;
+
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeAtStartForecast_h + i * timeStep_h;
+ double timeOfDay_h = t % 24.0;
+ double ambientTemp_degC = ambientTemperatureProfile.getValue(t);
+
+ // Same setpoint-selection logic as manageHeating, incl. the heating-season hysteresis
+ double currentSetpoint_degC = daySetpoint_degC;
+ if (avgTemp24h_degC > J_HeatingFunctionLibrary.heatingDaysAvgTempTreshold_degC) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ } else if (timeOfDay_h < dayStartTime_h || timeOfDay_h >= nightStartTime_h) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ }
+
+ // Same order of operations as manageHeating: filter first, then deltaT vs *previous* building temp
+ simFilteredSetpoint_degC += (timeStep_h / filterTimeScale_h) * (currentSetpoint_degC - simFilteredSetpoint_degC);
+ double deltaT_degC = simFilteredSetpoint_degC - simBuildingTemp_degC;
+ simIState_hDegC = max(0, simIState_hDegC + deltaT_degC * timeStep_h);
+ double heatingDemand_kW = max(0, deltaT_degC * pGain_kWpDegC + simIState_hDegC * iGain_kWphDegC);
+
+ buildingHeatDemandProfile_kW[i] = heatingDemand_kW;
+
+ // Advance building temperature under this heat input for the next step
+ double heatLoss_kW = (lossFactor_WpK * (simBuildingTemp_degC - ambientTemp_degC) / 1000) * lossScalingFactor_fr;
+ double netHeat_kW = heatingDemand_kW - heatLoss_kW;
+ simBuildingTemp_degC += (netHeat_kW / heatCapacity_kWhpK) * timeStep_h;
+ }
+
+ return buildingHeatDemandProfile_kW;
+ }
+
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java b/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java
index ef0eef4d..f35822c3 100644
--- a/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java
+++ b/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java
@@ -212,8 +212,7 @@ else if (gc.c_heatingAssets.get(1) instanceof J_EAConversionHeatPump) {
this.filteredCurrentSetpoint_degC = heatingPreferences.getMinComfortTemperature_degC();
this.isInitialized = true;
}
-
-
+
public void notInitialized() {
this.isInitialized = false;
}
@@ -234,6 +233,95 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] electricityLoadProfile_kW = new Double[timeStepsInForecast];
+ Double[] gasLoadProfile_kW = new Double[timeStepsInForecast];
+ J_ProfilePointer ambientTemperatureProfile = this.gc.energyModel.pp_ambientTemperature_degC;
+ J_ProfileForecaster ambientTempeartureForecast = this.gc.energyModel.pf_ambientTemperature_degC;
+ double[] buildingHeatDemand_kW = this.getBuildingHeatDemandProfile(timeOfIntervalStart_h, timeStepsInForecast, ambientTemperatureProfile, ambientTempeartureForecast);
+ double[] otherFixedHeatDemand_kW = this.gc.f_getFixedAssetForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h, OL_EnergyCarriers.HEAT, this.timeParameters);
+
+ double gasBurnerEfficiency_fr = this.gasBurnerAsset.getEta_r();
+ double gasBurnerMaxOutput_kW = this.gasBurnerAsset.getOutputCapacity_kW();
+ double heatpumpInputCapacity_kW = this.heatPumpAsset.getInputCapacity_kW();
+
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double totalHeatDemand_kW = buildingHeatDemand_kW[i] + otherFixedHeatDemand_kW[i];
+ double COP_fr = this.heatPumpAsset.calculateCOP(this.heatPumpAsset.getOutputTemperature_degC(), ambientTemperatureProfile.getValue(t));
+ if (COP_fr < 3.0) {
+ gasLoadProfile_kW[i] = min(gasBurnerMaxOutput_kW, totalHeatDemand_kW / gasBurnerEfficiency_fr);
+ electricityLoadProfile_kW[i] = max(0, (totalHeatDemand_kW - gasBurnerMaxOutput_kW) / COP_fr);
+ }
+ else {
+ electricityLoadProfile_kW[i] = min(heatpumpInputCapacity_kW, totalHeatDemand_kW / COP_fr);
+ gasLoadProfile_kW[i] = max(0, (totalHeatDemand_kW - heatpumpInputCapacity_kW * COP_fr) / gasBurnerEfficiency_fr);
+ }
+ }
+ loadMap.put(OL_EnergyCarriers.ELECTRICITY, electricityLoadProfile_kW);
+ loadMap.put(OL_EnergyCarriers.METHANE, gasLoadProfile_kW);
+ // Building is a flex asset so included in system bounds of heating management, but fixed profiles are not.
+ Double[] heatLoad = Arrays.stream(otherFixedHeatDemand_kW).map(d -> -d).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+ OL_ForecastStatus status = OL_ForecastStatus.ESTIMATED_FORECAST;
+ String reason = "PI & Building states based on current timestep. Building forecast simplified by omitting solar radiation & ventilation.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+
+ private double[] getBuildingHeatDemandProfile(double timeAtStartForecast_h, int timeStepsInForecast, J_ProfilePointer ambientTemperatureProfile, J_ProfileForecaster ambientTempeartureForecast) {
+ double[] buildingHeatDemandProfile_kW = new double[timeStepsInForecast];
+
+ double dayStartTime_h = this.heatingPreferences.getStartOfDayTime_h();
+ double nightStartTime_h = this.heatingPreferences.getStartOfNightTime_h();
+ double daySetpoint_degC = this.heatingPreferences.getDayTimeSetPoint_degC();
+ double nightSetpoint_degC = this.heatingPreferences.getNightTimeSetPoint_degC();
+ double avgTemp24h_degC = ambientTempeartureForecast.getForecast(); // Assumes timeAtStartForecast_h is current model time and forecasting horizon is 24h.
+
+ double simBuildingTemp_degC = this.building.getCurrentTemperature();
+ double simFilteredSetpoint_degC = this.filteredCurrentSetpoint_degC;
+ double simIState_hDegC = this.I_state_hDegC;
+
+ double pGain_kWpDegC = this.P_gain_kWpDegC;
+ double iGain_kWphDegC = this.I_gain_kWphDegC;
+ double filterTimeScale_h = this.setpointFilterTimeScale_h;
+ double timeStep_h = this.timeParameters.getTimeStep_h();
+
+ double lossFactor_WpK = this.building.getLossFactor_WpK();
+ double lossScalingFactor_fr = this.building.getLossScalingFactor_fr();
+ double heatCapacity_kWhpK = this.building.getHeatCapacity_JpK() / 3.6e6;
+
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeAtStartForecast_h + i * timeStep_h;
+ double timeOfDay_h = t % 24.0;
+ double ambientTemp_degC = ambientTemperatureProfile.getValue(t);
+
+ // Same setpoint-selection logic as manageHeating, incl. the heating-season hysteresis
+ double currentSetpoint_degC = daySetpoint_degC;
+ if (avgTemp24h_degC > J_HeatingFunctionLibrary.heatingDaysAvgTempTreshold_degC) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ } else if (timeOfDay_h < dayStartTime_h || timeOfDay_h >= nightStartTime_h) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ }
+
+ // Same order of operations as manageHeating: filter first, then deltaT vs *previous* building temp
+ simFilteredSetpoint_degC += (timeStep_h / filterTimeScale_h) * (currentSetpoint_degC - simFilteredSetpoint_degC);
+ double deltaT_degC = simFilteredSetpoint_degC - simBuildingTemp_degC;
+ simIState_hDegC = max(0, simIState_hDegC + deltaT_degC * timeStep_h);
+ double heatingDemand_kW = max(0, deltaT_degC * pGain_kWpDegC + simIState_hDegC * iGain_kWphDegC);
+
+ buildingHeatDemandProfile_kW[i] = heatingDemand_kW;
+
+ // Advance building temperature under this heat input for the next step
+ double heatLoss_kW = (lossFactor_WpK * (simBuildingTemp_degC - ambientTemp_degC) / 1000) * lossScalingFactor_fr;
+ double netHeat_kW = heatingDemand_kW - heatLoss_kW;
+ simBuildingTemp_degC += (netHeat_kW / heatCapacity_kWhpK) * timeStep_h;
+ }
+
+ return buildingHeatDemandProfile_kW;
+ }
+
//Get parentagent
public Agent getParentAgent() {
return this.gc;
diff --git a/_alp/Classes/Class.J_HeatingManagementProfileHybridHeatPump.java b/_alp/Classes/Class.J_HeatingManagementProfileHybridHeatPump.java
index 37666ecd..14ce2b32 100644
--- a/_alp/Classes/Class.J_HeatingManagementProfileHybridHeatPump.java
+++ b/_alp/Classes/Class.J_HeatingManagementProfileHybridHeatPump.java
@@ -134,16 +134,46 @@ public J_HeatingPreferences getHeatingPreferences() {
return this.heatingPreferences;
}
-
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] electricityLoadProfile_kW = new Double[timeStepsInForecast];
+ Double[] gasLoadProfile_kW = new Double[timeStepsInForecast];
+ J_ProfilePointer ambientTemperatureProfile = this.gc.energyModel.pp_ambientTemperature_degC;
+ double[] fixedHeatDemand_kW = this.gc.f_getFixedAssetForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h, OL_EnergyCarriers.HEAT, this.timeParameters);
+
+ double gasBurnerEfficiency_fr = this.gasBurnerAsset.getEta_r();
+ double gasBurnerMaxOutput_kW = this.gasBurnerAsset.getOutputCapacity_kW();
+ double heatpumpInputCapacity_kW = this.heatPumpAsset.getInputCapacity_kW();
+
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double totalHeatDemand_kW = fixedHeatDemand_kW[i];
+ double COP_fr = this.heatPumpAsset.calculateCOP(this.heatPumpAsset.getOutputTemperature_degC(), ambientTemperatureProfile.getValue(t));
+ if (COP_fr < 3.0) {
+ gasLoadProfile_kW[i] = min(gasBurnerMaxOutput_kW, totalHeatDemand_kW / gasBurnerEfficiency_fr);
+ electricityLoadProfile_kW[i] = max(0, (totalHeatDemand_kW - gasBurnerMaxOutput_kW) / COP_fr);
+ }
+ else {
+ electricityLoadProfile_kW[i] = min(heatpumpInputCapacity_kW, totalHeatDemand_kW / COP_fr);
+ gasLoadProfile_kW[i] = max(0, (totalHeatDemand_kW - heatpumpInputCapacity_kW * COP_fr) / gasBurnerEfficiency_fr);
+ }
+ }
+ loadMap.put(OL_EnergyCarriers.ELECTRICITY, electricityLoadProfile_kW);
+ loadMap.put(OL_EnergyCarriers.METHANE, gasLoadProfile_kW);
+ Double[] heatLoad = Arrays.stream(fixedHeatDemand_kW).map(d -> -d).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+
+ OL_ForecastStatus status = OL_ForecastStatus.PERFECT_FORECAST;
+ String reason = "Forecaster has perfect foresight into heat demand profiles and ambient temperatures.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
//Get parentagent
public Agent getParentAgent() {
return this.gc;
}
-
-
public void storeStatesAndReset() {
//Nothing to store/reset
}
@@ -151,7 +181,6 @@ public void restoreStates() {
//Nothing to store/reset
}
-
@Override
public String toString() {
return super.toString();
diff --git a/_alp/Classes/Class.J_HeatingManagementSimple.java b/_alp/Classes/Class.J_HeatingManagementSimple.java
index ef791085..a810afa4 100644
--- a/_alp/Classes/Class.J_HeatingManagementSimple.java
+++ b/_alp/Classes/Class.J_HeatingManagementSimple.java
@@ -216,7 +216,129 @@ public void initializeAssets() {
this.isInitialized = true;
}
-
+ public J_AssetTypeForecast getForecast(double timeOfIntervalStart_h, double timeOfIntervalEnd_h) {
+ Map loadMap = new HashMap<>();
+ int timeStepsInForecast = roundToInt((timeOfIntervalEnd_h - timeOfIntervalStart_h) / this.timeParameters.getTimeStep_h());
+ Double[] loadProfile_kW = new Double[timeStepsInForecast];
+ J_ProfilePointer ambientTemperatureProfile = this.gc.energyModel.pp_ambientTemperature_degC;
+ J_ProfileForecaster ambientTempeartureForecast = this.gc.energyModel.pf_ambientTemperature_degC;
+ double[] buildingHeatDemand_kW = this.getBuildingHeatDemandProfile(timeOfIntervalStart_h, timeStepsInForecast, ambientTemperatureProfile, ambientTempeartureForecast);
+ double[] otherFixedHeatDemand_kW = this.gc.f_getFixedAssetForecast(timeOfIntervalStart_h, timeOfIntervalEnd_h, OL_EnergyCarriers.HEAT, this.timeParameters);
+
+ // We switch over the heating type twice, first to set the EnergyCarrier
+ OL_EnergyCarriers EC;
+ switch (this.gc.f_getCurrentHeatingType()) {
+ case GAS_BURNER:
+ EC = OL_EnergyCarriers.METHANE;
+ break;
+ case HYDROGENBURNER:
+ EC = OL_EnergyCarriers.HYDROGEN;
+ break;
+ case LT_DISTRICTHEAT:
+ case ELECTRIC_HEATPUMP:
+ EC = OL_EnergyCarriers.ELECTRICITY;
+ break;
+ case DISTRICTHEAT:
+ Double[] heatLoad = Arrays.stream(buildingHeatDemand_kW).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+ if (this.building == null) {
+ String reason = "GC connected to districtheating, so all heat demand is import.";
+ return new J_AssetTypeForecast(J_HeatingManagementPIcontrol.class, loadMap, OL_ForecastStatus.PERFECT_FORECAST, reason);
+ }
+ else {
+ String reason = "GC connected to districtheating, so all heat demand is import. Building forecast simplified by omitting solar radiation & ventilation.";
+ return new J_AssetTypeForecast(J_HeatingManagementPIcontrol.class, loadMap, OL_ForecastStatus.ESTIMATED_FORECAST, reason);
+ }
+ default:
+ throw new RuntimeException(String.format("Tried to forecast J_HeatingManagementPIControl, but encountered an unexepected heating type %s in GC %s", this.gc.f_getCurrentHeatingType(), this.gc.p_gridConnectionID));
+ }
+
+ // Then to determine the profile.
+ // Here we make a distinction between fixed efficiency, and efficiency variable per timestep.
+ boolean fixedEfficiency = false;
+ double fixedEfficiency_fr = 1.0;
+ J_EAConversionHeatPump hp = null;
+ switch (this.gc.f_getCurrentHeatingType()) {
+ case LT_DISTRICTHEAT:
+ fixedEfficiency = true;
+ hp = ((J_EAConversionHeatPump)this.heatingAsset);
+ fixedEfficiency_fr = hp.getCOP();
+ break;
+ case GAS_BURNER:
+ case HYDROGENBURNER:
+ fixedEfficiency = true;
+ fixedEfficiency_fr = this.heatingAsset.getEta_r();
+ break;
+ case ELECTRIC_HEATPUMP:
+ hp = ((J_EAConversionHeatPump)this.heatingAsset);
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double heatDemand_kW = buildingHeatDemand_kW[i] + otherFixedHeatDemand_kW[i];
+ double efficiency_fr = hp.calculateCOP(hp.getOutputTemperature_degC(), ambientTemperatureProfile.getValue(t));
+ double load_kW = heatDemand_kW / efficiency_fr;
+ loadProfile_kW[i] = load_kW;
+ }
+ break;
+ }
+
+ if (fixedEfficiency) {
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeOfIntervalStart_h + i * timeParameters.getTimeStep_h();
+ double heatDemand_kW = buildingHeatDemand_kW[i] + otherFixedHeatDemand_kW[i];
+ double load_kW = heatDemand_kW / fixedEfficiency_fr;
+ loadProfile_kW[i] = load_kW;
+ }
+ }
+ loadMap.put(EC, loadProfile_kW);
+ // Building is a flex asset so included in system bounds of heating management, but fixed profiles are not.
+ Double[] heatLoad = Arrays.stream(otherFixedHeatDemand_kW).map(d -> -d).boxed().toArray(Double[]::new);
+ loadMap.put(OL_EnergyCarriers.HEAT, heatLoad);
+ if (this.building == null) {
+ OL_ForecastStatus status = OL_ForecastStatus.PERFECT_FORECAST;
+ String reason = "Forecast is perfect for GridConnections without ThermalBuilding.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+ else {
+ OL_ForecastStatus status = OL_ForecastStatus.ESTIMATED_FORECAST;
+ String reason = "Temperature & Building states based on current timestep. Building forecast simplified by omitting solar radiation & ventilation.";
+ return new J_AssetTypeForecast(I_HeatingManagement.class, loadMap, status, reason);
+ }
+ }
+
+ private double[] getBuildingHeatDemandProfile(double timeAtStartForecast_h, int timeStepsInForecast, J_ProfilePointer ambientTemperatureProfile, J_ProfileForecaster ambientTempeartureForecast) {
+ double[] buildingHeatDemandProfile_kW = new double[timeStepsInForecast];
+ if (this.building == null) {
+ return buildingHeatDemandProfile_kW;
+ }
+ double dayStartTime_h = this.heatingPreferences.getStartOfDayTime_h();
+ double nightStartTime_h = this.heatingPreferences.getStartOfNightTime_h();
+ double daySetpoint_degC = this.heatingPreferences.getDayTimeSetPoint_degC();
+ double nightSetpoint_degC = this.heatingPreferences.getNightTimeSetPoint_degC();
+ double avgTemp24h_degC = ambientTempeartureForecast.getForecast(); // Assumes timeAtStartForecast_h is current model time and forecasting horizon is 24h.
+ double timeStep_h = this.timeParameters.getTimeStep_h();
+
+ double lossFactor_WpK = this.building.getLossFactor_WpK();
+ double lossScalingFactor_fr = this.building.getLossScalingFactor_fr();
+ double heatCapacity_kWhpK = this.building.getHeatCapacity_JpK() / 3.6e6;
+
+ for (int i = 0; i < timeStepsInForecast; i++) {
+ double t = timeAtStartForecast_h + i * timeStep_h;
+ double timeOfDay_h = t % 24.0;
+ double ambientTemp_degC = ambientTemperatureProfile.getValue(t);
+
+ // Same setpoint-selection logic as manageHeating, incl. the heating-season hysteresis
+ double currentSetpoint_degC = daySetpoint_degC;
+ if (avgTemp24h_degC > J_HeatingFunctionLibrary.heatingDaysAvgTempTreshold_degC) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ } else if (timeOfDay_h < dayStartTime_h || timeOfDay_h >= nightStartTime_h) {
+ currentSetpoint_degC = nightSetpoint_degC;
+ }
+ double heatLoss_kW = (lossFactor_WpK * (currentSetpoint_degC - ambientTemp_degC) / 1000) * lossScalingFactor_fr;
+ buildingHeatDemandProfile_kW[i] = max(0, heatLoss_kW);
+ }
+ return buildingHeatDemandProfile_kW;
+ }
+
public void notInitialized() {
this.isInitialized = false;
}
diff --git a/_alp/Classes/Class.J_TimeParameters.java b/_alp/Classes/Class.J_TimeParameters.java
index 77c3bc31..ae5ccd0d 100644
--- a/_alp/Classes/Class.J_TimeParameters.java
+++ b/_alp/Classes/Class.J_TimeParameters.java
@@ -108,19 +108,19 @@ public double getRunDuration_h() {
//Static methods
public static OL_Days getDayFromDayIndex(int dayIndex){
switch(dayIndex) {
- case 0:
- return OL_Days.MONDAY;
case 1:
- return OL_Days.TUESDAY;
+ return OL_Days.MONDAY;
case 2:
- return OL_Days.WEDNESDAY;
+ return OL_Days.TUESDAY;
case 3:
- return OL_Days.THURSDAY;
+ return OL_Days.WEDNESDAY;
case 4:
- return OL_Days.FRIDAY;
+ return OL_Days.THURSDAY;
case 5:
- return OL_Days.SATURDAY;
+ return OL_Days.FRIDAY;
case 6:
+ return OL_Days.SATURDAY;
+ case 7:
return OL_Days.SUNDAY;
default:
throw new RuntimeException("Day found that should not exist.");
@@ -129,19 +129,19 @@ public static OL_Days getDayFromDayIndex(int dayIndex){
public static int getDayIndexFromDay(OL_Days day){
switch(day) {
case MONDAY:
- return 0;
- case TUESDAY:
return 1;
- case WEDNESDAY:
+ case TUESDAY:
return 2;
- case THURSDAY:
+ case WEDNESDAY:
return 3;
- case FRIDAY:
+ case THURSDAY:
return 4;
- case SATURDAY:
+ case FRIDAY:
return 5;
- case SUNDAY:
+ case SATURDAY:
return 6;
+ case SUNDAY:
+ return 7;
default:
throw new RuntimeException("Day found that should not exist.");
}
@@ -158,6 +158,19 @@ public static List getOrderedDaysList(){
);
}
+ public int getWeekIndex(double time_h) {
+ double offset = (this.getDayOfWeek1jan() - 1) * 24.0;
+ return (int) Math.floor((time_h + offset) / (7 * 24));
+ }
+
+ /*
+ * Note: This method can return a negative time for the first week if
+ */
+ public double getWeekStart_h(int weekIndex) {
+ double offset = (this.getDayOfWeek1jan() - 1) * 24.0;
+ return weekIndex * (7 * 24) - offset;
+ }
+
@Override
public String toString() {
return "J_TimeParameters{" +