From 8f191961c679d6ff0223925d4ab13748f328cab1 Mon Sep 17 00:00:00 2001 From: Luc-Sol Date: Fri, 28 Nov 2025 22:07:18 +0100 Subject: [PATCH 01/12] Introduced the new Interface I_ChargingRequests --- Zero_engine.alpx | 13 +- _alp/Agents/EnergyModel/EmbeddedObjects.xml | 27 + .../AOC.GCDistrictHeating.xml | 3 + .../AOC.GCEnergyConversion.xml | 3 + .../AOC.GCEnergyProduction.xml | 3 + .../GCGridBattery/AOC.GCGridBattery.xml | 3 + _alp/Agents/GCHouse/AOC.GCHouse.xml | 3 + _alp/Agents/GCIndustry/AOC.GCIndustry.xml | 3 + .../GCNeighborhood/AOC.GCNeighborhood.xml | 3 + .../GCPublicCharger/AOC.GCPublicCharger.xml | 3 + _alp/Agents/GCUtility/AOC.GCUtility.xml | 3 + _alp/Agents/GridConnection/Variables.xml | 25 + _alp/Classes/Class.I_ChargingRequest.java | 31 + .../Class.J_ChargingManagementSimple.java | 8 + _alp/Classes/Class.J_ChargingSession.java | 45 +- _alp/Classes/Class.J_EAChargePoint.java | 542 ++++++------------ _alp/Classes/Class.J_EAChargePoint_OLD.java | 385 +++++++++++++ 17 files changed, 723 insertions(+), 380 deletions(-) create mode 100644 _alp/Classes/Class.I_ChargingRequest.java create mode 100644 _alp/Classes/Class.J_EAChargePoint_OLD.java diff --git a/Zero_engine.alpx b/Zero_engine.alpx index 0e7def33..4e5f85b6 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1704,7 +1704,8 @@ 1755171209007 - + + true 1752677832758 @@ -1792,6 +1793,16 @@ 1752680962144 + + 1764337491572 + + 1762850586274 + + + 1764337836818 + + 1752677832758 + com.anylogic.libraries.modules.markup_descriptors diff --git a/_alp/Agents/EnergyModel/EmbeddedObjects.xml b/_alp/Agents/EnergyModel/EmbeddedObjects.xml index 8ca89240..7e5882f8 100644 --- a/_alp/Agents/EnergyModel/EmbeddedObjects.xml +++ b/_alp/Agents/EnergyModel/EmbeddedObjects.xml @@ -226,6 +226,9 @@ + + + true @@ -1011,6 +1014,9 @@ + + + true @@ -1155,6 +1161,9 @@ + + + true @@ -1293,6 +1302,9 @@ + + + true @@ -1488,6 +1500,9 @@ + + + true @@ -1623,6 +1638,9 @@ + + + true @@ -1761,6 +1779,9 @@ + + + true @@ -2268,6 +2289,9 @@ + + + true @@ -2440,6 +2464,9 @@ + + + true diff --git a/_alp/Agents/GCDistrictHeating/AOC.GCDistrictHeating.xml b/_alp/Agents/GCDistrictHeating/AOC.GCDistrictHeating.xml index 1e710fa8..18868479 100644 --- a/_alp/Agents/GCDistrictHeating/AOC.GCDistrictHeating.xml +++ b/_alp/Agents/GCDistrictHeating/AOC.GCDistrictHeating.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCEnergyConversion/AOC.GCEnergyConversion.xml b/_alp/Agents/GCEnergyConversion/AOC.GCEnergyConversion.xml index c8bb354a..1995d7e2 100644 --- a/_alp/Agents/GCEnergyConversion/AOC.GCEnergyConversion.xml +++ b/_alp/Agents/GCEnergyConversion/AOC.GCEnergyConversion.xml @@ -88,6 +88,9 @@ + + + false diff --git a/_alp/Agents/GCEnergyProduction/AOC.GCEnergyProduction.xml b/_alp/Agents/GCEnergyProduction/AOC.GCEnergyProduction.xml index 544fbdfb..cc7439d4 100644 --- a/_alp/Agents/GCEnergyProduction/AOC.GCEnergyProduction.xml +++ b/_alp/Agents/GCEnergyProduction/AOC.GCEnergyProduction.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCGridBattery/AOC.GCGridBattery.xml b/_alp/Agents/GCGridBattery/AOC.GCGridBattery.xml index 43f36c37..cf6a418b 100644 --- a/_alp/Agents/GCGridBattery/AOC.GCGridBattery.xml +++ b/_alp/Agents/GCGridBattery/AOC.GCGridBattery.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCHouse/AOC.GCHouse.xml b/_alp/Agents/GCHouse/AOC.GCHouse.xml index a46ac2da..c16e98c9 100644 --- a/_alp/Agents/GCHouse/AOC.GCHouse.xml +++ b/_alp/Agents/GCHouse/AOC.GCHouse.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCIndustry/AOC.GCIndustry.xml b/_alp/Agents/GCIndustry/AOC.GCIndustry.xml index 7deb1fb3..186a0cd4 100644 --- a/_alp/Agents/GCIndustry/AOC.GCIndustry.xml +++ b/_alp/Agents/GCIndustry/AOC.GCIndustry.xml @@ -88,6 +88,9 @@ + + + false diff --git a/_alp/Agents/GCNeighborhood/AOC.GCNeighborhood.xml b/_alp/Agents/GCNeighborhood/AOC.GCNeighborhood.xml index caad126c..22cf2098 100644 --- a/_alp/Agents/GCNeighborhood/AOC.GCNeighborhood.xml +++ b/_alp/Agents/GCNeighborhood/AOC.GCNeighborhood.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCPublicCharger/AOC.GCPublicCharger.xml b/_alp/Agents/GCPublicCharger/AOC.GCPublicCharger.xml index e2f01783..f454f1d1 100644 --- a/_alp/Agents/GCPublicCharger/AOC.GCPublicCharger.xml +++ b/_alp/Agents/GCPublicCharger/AOC.GCPublicCharger.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GCUtility/AOC.GCUtility.xml b/_alp/Agents/GCUtility/AOC.GCUtility.xml index 7b9d9474..0e8c372b 100644 --- a/_alp/Agents/GCUtility/AOC.GCUtility.xml +++ b/_alp/Agents/GCUtility/AOC.GCUtility.xml @@ -87,6 +87,9 @@ + + + false diff --git a/_alp/Agents/GridConnection/Variables.xml b/_alp/Agents/GridConnection/Variables.xml index 68459047..dee6f289 100644 --- a/_alp/Agents/GridConnection/Variables.xml +++ b/_alp/Agents/GridConnection/Variables.xml @@ -1292,6 +1292,31 @@ + + 1764341158977 + + 600 + 820 + + false + true + true + + + NONE + false + + 1764341158975 + TEXT_BOX + 0 + 100 + NO_DELIMETER + + + 1659962626903 diff --git a/_alp/Classes/Class.I_ChargingRequest.java b/_alp/Classes/Class.I_ChargingRequest.java new file mode 100644 index 00000000..b1aa5ba2 --- /dev/null +++ b/_alp/Classes/Class.I_ChargingRequest.java @@ -0,0 +1,31 @@ +/** + * I_ChargingRequest + */ +public interface I_ChargingRequest { + + // The maximal capacity for the vehicle + public double getChargingCapacity_kW(); + + public double getCurrentSOC_kWh(); + + public double getMaxSOC_kWh(); + + // Last moment before full power charging is required + public double getChargeDeadline_h(); + + public double getLeaveTime_h(); + + public boolean getV2GCapable(); + + // The total energy needed before the leave time + public double getEnergyNeededForNextTrip_kWh(); + + // The remaining energy needed before the leave time + public double getRemainingChargeDemand_kWh(); + + public double getVehicleScaling_fr(); + + // Sends the power into the EV/ChargingSession to update the SOC, ChargeDeadline etc... + public double charge_kW( double charge_kW ); + +} \ No newline at end of file diff --git a/_alp/Classes/Class.J_ChargingManagementSimple.java b/_alp/Classes/Class.J_ChargingManagementSimple.java index b5814407..261a0518 100644 --- a/_alp/Classes/Class.J_ChargingManagementSimple.java +++ b/_alp/Classes/Class.J_ChargingManagementSimple.java @@ -18,6 +18,7 @@ public class J_ChargingManagementSimple implements I_ChargingManagement { private GridConnection gc; private OL_ChargingAttitude activeChargingType = OL_ChargingAttitude.SIMPLE; private boolean V2GActive = false; + private J_EAChargePoint chargePoint; /** * Default constructor @@ -28,6 +29,7 @@ public J_ChargingManagementSimple() { public J_ChargingManagementSimple( GridConnection gc ) { this.gc = gc; + this.chargePoint = gc.p_chargePoint; } public OL_ChargingAttitude getCurrentChargingType() { @@ -39,6 +41,12 @@ public OL_ChargingAttitude getCurrentChargingType() { * */ public void manageCharging() { + if (this.chargePoint == null) { + if (gc.p_chargePoint == null) { + throw new RuntimeException("Impossible to charge without chargepoint."); + } + this.chargePoint = gc.p_chargePoint; + } double t_h = gc.energyModel.t_h; for (J_EAEV ev : gc.c_electricVehicles) { if (ev.available) { diff --git a/_alp/Classes/Class.J_ChargingSession.java b/_alp/Classes/Class.J_ChargingSession.java index 72b6fb01..077d2ee7 100644 --- a/_alp/Classes/Class.J_ChargingSession.java +++ b/_alp/Classes/Class.J_ChargingSession.java @@ -13,8 +13,8 @@ public class J_ChargingSession implements Serializable { double vehicleMaxChargingPower_kW; int socketNb; - //boolean V1GCapable = true; - //boolean V2GCapable = true; + boolean V1GCapable = true; + boolean V2GCapable = true; double chargedDuringSession_kWh = 0; double dischargedDuringSession_kWh = 0; @@ -39,8 +39,9 @@ public J_ChargingSession(double startTime_quarterhours, double endTime_quarterho new RuntimeException("StartTime is later then the endtime for J_ChargingSession"); } } - - public double charge(double chargeSetpoint_kW) { + + + public double charge_kW(double chargeSetpoint_kW) { double actualChargePower_kW = max(min(chargeSetpoint_kW, (batterySize_kWh - stateOfCharge_kWh) / timeStep_h), -stateOfCharge_kWh / timeStep_h); // Limit charge power to stay within SoC 0-100 stateOfCharge_kWh += actualChargePower_kW * timeStep_h; chargedDuringSession_kWh+=max(0, actualChargePower_kW*this.timeStep_h); @@ -48,6 +49,34 @@ public double charge(double chargeSetpoint_kW) { return actualChargePower_kW; } + public double getLeaveTime_h() { + return this.endTime_h; + } + + public double getChargingCapacity_kW() { + return this.vehicleMaxChargingPower_kW; + } + + public double getCurrentSOC_kWh() { + return this.stateOfCharge_kWh; + } + + public double getMaxSOC_kWh() { + return this.batterySize_kWh; + } + + public double getChargeDeadline_h() { + double chargeNeedForNextTrip_kWh = max(0, this.getEnergyNeededForNextTrip_kWh() - this.getCurrentSOC_kWh()); + double chargeTimeMargin_h = 0.5; // Margin to be ready with charging before start of next trip + double chargeDeadline_h = this.endTime_h - chargeNeedForNextTrip_kWh / this.vehicleMaxChargingPower_kW - chargeTimeMargin_h; + return chargeDeadline_h; + } + + + public double getEnergyNeededForNextTrip_kWh() { + return this.chargingDemand_kWh; + } + public double getRemainingChargeDemand_kWh() { return chargingDemand_kWh - chargedDuringSession_kWh + dischargedDuringSession_kWh; } @@ -56,6 +85,14 @@ public J_ChargingSession getClone() { return new J_ChargingSession((this.startTime_h*4), (this.endTime_h*4), this.chargingDemand_kWh, this.batterySize_kWh, this.vehicleMaxChargingPower_kW, this.socketNb, this.timeStep_h); } + public double getVehicleScaling_fr() { + return 1.0; + } + + public boolean getV2GCapable() { + return this.V2GCapable; + } + @Override public String toString() { diff --git a/_alp/Classes/Class.J_EAChargePoint.java b/_alp/Classes/Class.J_EAChargePoint.java index b62a6334..fec84388 100644 --- a/_alp/Classes/Class.J_EAChargePoint.java +++ b/_alp/Classes/Class.J_EAChargePoint.java @@ -1,385 +1,177 @@ /** * J_EAChargePoint */ -public class J_EAChargePoint extends zero_engine.J_EA implements Serializable { - public double discharged_kWh; - public double charged_kWh; - public double capacityElectric_kW; - public List chargeSessionList; - private boolean V1GCapable; - private boolean V2GCapable; - private boolean V2GActive = false; - private int nbSockets; - private int[] nextSessionIdxs;// = 0; - - private J_ChargingSession[] currentChargingSessions; - - private int currentNumberOfChargingSockets = 0; // Used for certain charging algorithms - - // For filtered price - private double electricityPriceLowPassed_eurpkWh = 0.1; - private double priceFilterTimeScale_h = 5*24; - - // - private double dischargedStored_kWh; - private double chargedStored_kWh; - private J_ChargingSession[] currentChargingSessionsStored; - private int[] nextSessionIdxsStored; - - //Charging attitude - private OL_ChargingAttitude chargingAttitude = OL_ChargingAttitude.SIMPLE; - - /** - * Default constructor - */ - public J_EAChargePoint(Agent parentAgent, double electricCapacity_kW, double timestep_h, List chargeSessionList, boolean V1GCapable, boolean V2GCapable, int nbSockets) { - this.parentAgent = parentAgent; - this.capacityElectric_kW = electricCapacity_kW; - this.timestep_h = timestep_h; - this.chargeSessionList = chargeSessionList; - this.V1GCapable = V1GCapable; - this.V2GCapable = V2GCapable; - this.activeProductionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); - this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); - if(V2GCapable && this.V2GActive) { - this.assetFlowCategory = OL_AssetFlowCategories.V2GPower_kW; - } else { - this.assetFlowCategory = OL_AssetFlowCategories.evChargingPower_kW; - } - this.nbSockets = nbSockets; - this.currentChargingSessions = new J_ChargingSession[nbSockets]; - this.nextSessionIdxs = new int[nbSockets]; - this.registerEnergyAsset(); - } - - public void f_updateAllFlows( double t_h) { +public class J_EAChargePoint extends J_EA implements Serializable { - double currentElectricityPriceConsumption_eurpkWh = ((GridConnection)parentAgent).energyModel.pp_dayAheadElectricityPricing_eurpMWh.getCurrentValue() * 0.001; - this.electricityPriceLowPassed_eurpkWh += (currentElectricityPriceConsumption_eurpkWh-electricityPriceLowPassed_eurpkWh) / (priceFilterTimeScale_h/timestep_h); + private boolean hasSocketRestrictions; + private int nbSockets; + private double totalCapacity_kW; + private List socketCapacities_kW; + private boolean V1GCapable; + private boolean V2GCapable; + private boolean V2GActive; + private List chargeSessionList; + private int chargeSessionIndex = 0; + + private List currentActiveChargingRequests = new ArrayList<>(); + + private double currentChargePower_kW; + private double currentDischargePower_kW; + + private int chargeSessionIndexStored; + private List storedActiveChargingRequests = null; + /** + * Default constructor + * No restrictions on sockets + */ + public J_EAChargePoint( Agent parentAgent, OL_EnergyAssetType energyAssetType, List chargeSessionList, boolean V1GCapable, boolean V2GCapable ) { + // moet de lijst met sessies in de constructor? of willen we deze in de gc opslaan? of iets anders? + this.parentAgent = parentAgent; + this.energyAssetType = energyAssetType; + this.chargeSessionList = chargeSessionList; + this.V1GCapable = V1GCapable; + this.V2GCapable = V2GCapable; + + this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + if (V2GCapable) { + this.activeProductionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + } + + this.hasSocketRestrictions = false; + } + + /** + * With restrictions on sockets + */ + public J_EAChargePoint( Agent parentAgent, OL_EnergyAssetType energyAssetType, List chargeSessionList, boolean V1GCapable, boolean V2GCapable, List socketCapacities_kW) { + this.parentAgent = parentAgent; + this.energyAssetType = energyAssetType; + this.chargeSessionList = chargeSessionList; + this.V1GCapable = V1GCapable; + this.V2GCapable = V2GCapable; + + this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + if (V2GCapable) { + this.activeProductionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + } + + this.addSocketRestrictions(socketCapacities_kW, totalCapacity_kW); + } + + public void addSocketRestrictions( List socketCapacities_kW, double totalCapacity_kW ) { + this.hasSocketRestrictions = true; + this.socketCapacities_kW = socketCapacities_kW; + this.totalCapacity_kW = totalCapacity_kW; + } + + public void manageSockets( List charges_kW ) { + this.currentChargePower_kW = 0; + this.currentDischargePower_kW = 0; + for (int i = 0; i < this.currentActiveChargingRequests.size(); i++) { + if (charges_kW.get(i) < 0 && (!this.V2GCapable || !this.V2GActive)) { + // kan dit niet? of moet het gewoon gezet worden op 0? + throw new RuntimeException("kann niee"); + } + double x = this.currentActiveChargingRequests.get(i).charge_kW( charges_kW.get(i)); - /*if (gridAwareMode) { // Add gridload-factor to current price - currentElectricityPriceConsumption_eurpkWh = currentElectricityPriceConsumption_eurpkWh + (max(0,((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW-0.5))*0.1; - if ( ((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW > 0.5) { - //traceln("Adding %s eurpkWh to charging price to prevent congestion", (((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW-0.5)*1); - } - }*/ - - // Check if V2G is activated and the charger is capable - boolean doV2G = this.V2GActive && this.V2GCapable; - - // Update the J_ChargingSessions of the sockets - for (int i = 0; i= currentChargingSessions[i].startTime_h) { - power_kW += this.operateChargerSocket(i, t_h, currentElectricityPriceConsumption_eurpkWh, doV2G); - discharged_kWh += min(0,-power_kW) * timestep_h; - charged_kWh += max(0,power_kW) * timestep_h; - currentNumberOfChargingSockets++; - } - } - - // Call the regular J_EA updateAllFlows and operate - this.v_powerFraction_fr = power_kW / this.capacityElectric_kW; - super.f_updateAllFlows( ); - return; - } - - @Override - public void operate(double ratioOfCapacity) { - - double charge_kW = ratioOfCapacity * capacityElectric_kW; - - double electricityProduction_kW = max(-charge_kW, 0); - double electricityConsumption_kW = max(charge_kW, 0); - - energyUse_kW = electricityConsumption_kW - electricityProduction_kW; - energyUsed_kWh += energyUse_kW * timestep_h; - - flowsMap.put(OL_EnergyCarriers.ELECTRICITY, electricityConsumption_kW - electricityProduction_kW); - // Split charging and discharing power 'at the source'! - - if (charge_kW > 0) { // charging - assetFlowsMap.put(OL_AssetFlowCategories.evChargingPower_kW, electricityConsumption_kW); - } else if(charge_kW < 0){ - if(this.V2GCapable) { // && this.V2GActive) { - assetFlowsMap.put(OL_AssetFlowCategories.V2GPower_kW, electricityProduction_kW); - } - else { - traceln("Charge power in J_EAChargePoint negative: %s", charge_kW); - throw new RuntimeException("Trying to discharge into a charger, that does not have the capability or where v2g is not activated!"); - } - } - } - - - private double operateChargerSocket(int socketNb, double t_h, double currentElectricityPriceConsumption_eurpkWh, boolean doV2G) { - double chargeSetpoint_kW = 0; - if(!this.V1GCapable) { - chargeSetpoint_kW = determineChargeSetpoint_simple_kW(socketNb); - } - else { - switch(this.chargingAttitude) { - case SIMPLE: - chargeSetpoint_kW = determineChargeSetpoint_simple_kW(socketNb); - break; - case PRICE: - chargeSetpoint_kW = determineChargeSetpoint_price_kW(socketNb, t_h, doV2G, currentElectricityPriceConsumption_eurpkWh); - break; - case BALANCE_LOCAL: - throw new RuntimeException("BALANCE LOCAL CHARGING STRATEGY HAS NOT BEEN CREATED YET FOR CHARGEPOINTS"); - //chargeSetpoint_kW = determineChargeSetpoint_balanceLocal_kW(socketNb, t_h, doV2G); - case BALANCE_GRID: - chargeSetpoint_kW = determineChargeSetpoint_balanceGrid_kW(socketNb, t_h, doV2G); - break; - default: - throw new RuntimeException("UNSUPPORTED CHARGING ATTITUDE SELECTED FOR CHARGEPOINT"); - } - } - - return currentChargingSessions[socketNb].charge(chargeSetpoint_kW); - } - - - private double determineChargeSetpoint_simple_kW(int socketNb) { - double maxChargePower = capacityElectric_kW;//min(currentChargingSessions[socketNb].vehicleMaxChargingPower_kW, capacityElectric_kW); - double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! - double chargeSetpoint_kW = max(0, min(maxChargePower, remainingChargeDemand_kWh/timestep_h)); - - return chargeSetpoint_kW; - } - - private double determineChargeSetpoint_price_kW(int socketNb, double t_h, boolean doV2G, double currentElectricityPriceConsumption_eurpkWh) { - double maxChargePower = capacityElectric_kW;//min(currentChargingSessions[socketNb].vehicleMaxChargingPower_kW, capacityElectric_kW); - double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! - double chargeSetpoint_kW = 0; + // check socket capacity? + this.currentChargePower_kW += max(0, x); + this.currentDischargePower_kW += max(0, -x); + } - //traceln("Smart charging active at chargePoint"); - double nextTripStartTime_h = currentChargingSessions[socketNb].endTime_h; - double chargeTimeMargin_h = 0.5; // Margin to be ready with charging before start of next trip - double chargeDeadline_h = nextTripStartTime_h - remainingChargeDemand_kWh / maxChargePower - chargeTimeMargin_h; - double remainingFlexTime_h = chargeDeadline_h - t_h; // measure of flexiblity left in current charging session. + // The management class should never have all the charging sessions go over the total available capacity, so this is a safety check + if (this.hasSocketRestrictions) { + if (this.currentChargePower_kW > this.totalCapacity_kW || this.currentDischargePower_kW > this.totalCapacity_kW) { + // kan dit niet? of moet het gewoon gecapt worden? + throw new RuntimeException("klopt niet"); + } + } + + double chargePower_kW = this.currentChargePower_kW + this.currentDischargePower_kW; + this.f_updateAllFlows(chargePower_kW); - if ( t_h >= chargeDeadline_h && remainingChargeDemand_kWh > 0) { // Must-charge time at max charging power - //traceln("Urgency charging on charge point GC: %s! May exceed connection capacity!", this.parentAgent); - chargeSetpoint_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); - } else { - double WTPoffset_eurpkW = 0.01; // Drops willingness to pay price for charging, combined with remainingFlexTime_h. - double WTPCharging_eurpkWh = electricityPriceLowPassed_eurpkWh - WTPoffset_eurpkW * remainingFlexTime_h; //+ urgencyGain_eurpkWh * ( max(0,maxSpreadChargingPower_kW) / ev.getCapacityElectric_kW() ); // Scale WTP based on flexibility expressed in terms of power-fraction - //WTPprice_eurpkWh = WTPoffset_eurpkWh + (main.v_epexNext24hours_eurpkWh+v_electricityPriceLowPassed_eurpkWh)/2 + flexibilityGain_eurpkWh * sqrt(maxSpreadChargingPower_kW/maxChargingPower_kW); - double priceGain_r = 0.5; // When WTP is higher than current electricity price, ramp up charging power with this gain based on the price-delta. - chargeSetpoint_kW = max(0, maxChargePower * min(1,(WTPCharging_eurpkWh / currentElectricityPriceConsumption_eurpkWh - 1) * priceGain_r)); // min(1,...) is needed to prevent devide by zero leading to infinity/NaN results. - if ( doV2G && remainingFlexTime_h > 1 && chargeSetpoint_kW == 0 ) { // Surpluss SOC and high energy price - //traceln("Conditions for V2G met in chargePoint"); - double V2G_WTS_offset_eurpkWh = 0.02; // Price must be at least this amount above the moving average to decide to discharge EV battery. - double WTSV2G_eurpkWh = V2G_WTS_offset_eurpkWh + electricityPriceLowPassed_eurpkWh; // Can become zero!! - chargeSetpoint_kW = min(0, -maxChargePower * min(1,(currentElectricityPriceConsumption_eurpkWh / WTSV2G_eurpkWh - 1) * priceGain_r)); // min(1,...) is needed to prevent devide by zero leading to infinity/NaN results. - //if (chargeSetpoint_kW < 0) {traceln(" V2G Active! Power: " + chargeSetpoint_kW );} - } - } - - return chargeSetpoint_kW; - } - - private double determineChargeSetpoint_balanceLocal_kW(int socketNb, double t_h, boolean doV2G) { - // DOES NOT MAKE SENSE TO USE THIS FOR GCPUBLIC CHARGER, ONLY FOR GC THAT HAVE THEIR OWN CONSUMPTION -> WHICH SHOULD BE SUPPORTED EVENTUALLY - if( parentAgent instanceof GCPublicCharger) { - throw new RuntimeException("This strategy only works for GCs that have their own consumption, do not use this for GCPublicChargers"); - } - - //CREATE STRATEGY HERE - double chargeSetpoint_kW = 0; + } + + @Override + public void f_updateAllFlows(double chargePower_kW) { + operate(chargePower_kW); + if (parentAgent instanceof GridConnection) { + ((GridConnection)parentAgent).f_addFlows(flowsMap, this.energyUse_kW, assetFlowsMap, this); + } + this.lastFlowsMap.cloneMap(this.flowsMap); + this.lastEnergyUse_kW = this.energyUse_kW; + this.clear(); + } - return chargeSetpoint_kW; - } - - private double determineChargeSetpoint_balanceGrid_kW(int socketNb, double t_h, boolean doV2G) { - double chargeSetpoint_kW = 0; - double maxChargePower = capacityElectric_kW; - double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! + @Override + public void operate(double chargePower_kW) { + flowsMap.put(OL_EnergyCarriers.ELECTRICITY, chargePower_kW); + // Split charging and discharing power 'at the source'! + assetFlowsMap.put(OL_AssetFlowCategories.evChargingPower_kW, this.totalChargePower_kW); + if (this.V2GCapable && this.V2GActive) { + assetFlowsMap.put(OL_AssetFlowCategories.V2GPower_kW, this.totalDischargePower_kW); + } + } + + // This function is called every timestep before the management function + public void updateActiveChargingRequests() { + // Remove all charging requests that are finished + List finishedChargingRequests = new ArrayList<>(); + for (I_ChargingRequest chargingRequest : this.currentActiveChargingRequests) { + // here we will use the soon to be global parameter current time + if ( t_h >= chargingRequest.getLeaveTime_h() ) { + finishedChargingRequests.add(chargingRequest); + } + } + this.currentActiveChargingRequests.removeAll(finishedChargingRequests); + // Find if there are new charging requests + // Vehicles + for (J_EAEV ev : ((GridConnection)parentAgent).c_electricVehicles) { + if (ev.getAvailability() && !this.currentActiveChargingRequests.contains(ev) ) { + this.addChargingRequest(ev); + } + } + // ChargingSessions + while ( t_h <= chargeSessionList.get(chargeSessionIndex).startTime_h ) { + this.addChargingRequest(chargeSessionList.get(chargeSessionIndex)); + chargeSessionIndex++; + } + } + + public void addChargingRequest( I_ChargingRequest chargingRequest ) { + // TODO: (Longterm) Make this more complex when we need to take socket restrictions into account. + this.currentActiveChargingRequests.add(chargingRequest); + } + + @Override + public void storeStatesAndReset() { + // TODO: Finish this !! + this.chargeSessionIndexStored = this.chargeSessionIndex; + this.chargeSessionIndex = 0; + this.storedActiveChargingRequests = currentActiveChargingRequests; + currentActiveChargingRequests = new ArrayList<>(); + energyUsedStored_kWh = energyUsed_kWh; + energyUsed_kWh = 0.0; + clear(); + } + + @Override + public void restoreStates() { + // TODO: Finish this !! + chargeSessionIndex = chargeSessionIndexStored; + currentActiveChargingRequests = storedActiveChargingRequests; + energyUsed_kWh = energyUsedStored_kWh; + } + + @Override + public String toString() { + return super.toString(); + } - GridNode parentNode = ((GridConnection)parentAgent).p_parentNodeElectric; - double currentBalanceOnGridNodeWithoutEV_kW = parentNode.v_currentLoad_kW - parentNode.v_currentChargingPower_kW; - double gridNodeLowPassedLoad_kW = parentNode.v_lowPassedLoadFilter_kW; - - double nextTripStartTime_h = currentChargingSessions[socketNb].endTime_h; - double chargeTimeMargin_h = 0.5; // Margin to be ready with charging before start of next trip - double chargeDeadline_h = nextTripStartTime_h - remainingChargeDemand_kWh / maxChargePower - chargeTimeMargin_h; - double remainingFlexTime_h = chargeDeadline_h - t_h; // measure of flexiblity left in current charging session. - double remainingTimeToCharge = nextTripStartTime_h - t_h - chargeTimeMargin_h; - - /*double avgPowerDemandTillTrip_kW = 0; - if(remainingTimeToCharge != 0) { - avgPowerDemandTillTrip_kW = remainingChargeDemand_kWh / (nextTripStartTime_h - t_h - chargeTimeMargin_h); - } - else if(remainingChargeDemand_kWh > 0) { - avgPowerDemandTillTrip_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); - }*/ - - if ( t_h >= chargeDeadline_h && remainingChargeDemand_kWh > 0) { // Must-charge time at max charging power - chargeSetpoint_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); - } else { - double flexGain_r_manual = 0.8; - double flexGain_r = 1/max(1, (double)parentNode.v_currentNumberOfChargingChargePoints) * flexGain_r_manual; // how strongly to 'follow' currentBalanceBeforeEV_kW -> influenced by the amount of charging chargers at this momment - chargeSetpoint_kW = max(0, currentChargingSessions[socketNb].avgPowerDemand_kW + (gridNodeLowPassedLoad_kW - currentBalanceOnGridNodeWithoutEV_kW) * (min(1,flexGain_r))); - if ( doV2G && remainingFlexTime_h > 1 && chargeSetpoint_kW == 0 ) { // Surpluss flexibility - chargeSetpoint_kW = min(0, currentChargingSessions[socketNb].avgPowerDemand_kW + (gridNodeLowPassedLoad_kW - currentBalanceOnGridNodeWithoutEV_kW) * (min(1,flexGain_r))); - } - } - return chargeSetpoint_kW; - } - + /** + * This number is here for model snapshot storing purpose
+ * It needs to be changed when this class gets changed + */ + private static final long serialVersionUID = 1L; - - private void manageSocket(int socketNb, double t_h) { - if (this.currentChargingSessions[socketNb] != null && t_h >= this.currentChargingSessions[socketNb].endTime_h) { // end session - if (this.currentChargingSessions[socketNb].getRemainingChargeDemand_kWh() > 0.001 ) { traceln("!!Chargesession ended but charge demand not fullfilled!! Remaining demand: %s kWh", this.currentChargingSessions[socketNb].getRemainingChargeDemand_kWh()); } - this.currentChargingSessions[socketNb] = null; - } - - - if ( this.currentChargingSessions[socketNb] == null ) { // socket currently free - // check if we are not already past the last charging session. - // Find next charging session on this socket - - while (this.nextSessionIdxs[socketNb] < this.chargeSessionList.size() && this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).socketNb != socketNb) { - this.nextSessionIdxs[socketNb]++; - } - - if (this.nextSessionIdxs[socketNb] >= this.chargeSessionList.size()) { // no more sessions available - //traceln("Reached end of charging session list!"); - return; - } else { - this.currentChargingSessions[socketNb] = this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).getClone(); - - if (t_h > this.currentChargingSessions[socketNb].startTime_h) { - traceln("Chargesession %s started %s hours too late!", this.nextSessionIdxs[socketNb], t_h - this.currentChargingSessions[socketNb].startTime_h); - if (t_h >= this.currentChargingSessions[socketNb].endTime_h) { - traceln("!!Chargesession started after its endTime_h!! WTF?"); - } - } - this.nextSessionIdxs[socketNb]++; - } - } - } - - - public void fastForwardCharingSessions(double t_h) { - for (int socketNb = 0; socketNb= this.chargeSessionList.size()) { // no more sessions available - break; - } else { // Clone upcomming charger session and increase next session index - this.currentChargingSessions[socketNb] = this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).getClone(); - this.nextSessionIdxs[socketNb]++; - } - } - } - - - public void setV1GCapability(boolean V1GCapable) { - this.V1GCapable = V1GCapable; - } - public void setV2GCapability(boolean V2GCapable) { - this.V2GCapable = V2GCapable; - this.updateAssetFlowCategory(); - } - public boolean getV1GCapable() { - return this.V1GCapable; - - } - public boolean getV2GCapable() { - return this.V2GCapable; - - } - - public void setChargingAttitude(OL_ChargingAttitude chargingAttitude) { - this.chargingAttitude = chargingAttitude; - } - - public OL_ChargingAttitude getChargingAttitude() { - return this.chargingAttitude; - } - - public void setV2GActive(boolean activateV2G) { - this.V2GActive = activateV2G; - this.updateAssetFlowCategory(); - } - - public boolean getV2GActive() { - return this.V2GActive; - } - - private void updateAssetFlowCategory() { - if(this.V2GCapable && this.V2GActive) { - this.assetFlowCategory = OL_AssetFlowCategories.V2GPower_kW; - } - else { - this.assetFlowCategory = OL_AssetFlowCategories.evChargingPower_kW; - } - } - - public int getCurrentNumberOfChargingSockets() { - return this.currentNumberOfChargingSockets; - } - - @Override - public void storeStatesAndReset() { - energyUsedStored_kWh = energyUsed_kWh; - energyUsed_kWh = 0.0; - dischargedStored_kWh = discharged_kWh; - discharged_kWh = 0.0; - chargedStored_kWh = charged_kWh; - charged_kWh = 0.0; - - currentChargingSessionsStored = currentChargingSessions.clone(); - Arrays.fill(currentChargingSessions, null); - - nextSessionIdxsStored = nextSessionIdxs; - nextSessionIdxs = new int[nextSessionIdxsStored.length]; - - clear(); - } - - @Override - public void restoreStates() { - energyUsed_kWh = energyUsedStored_kWh; - discharged_kWh = dischargedStored_kWh; - charged_kWh = chargedStored_kWh; - - currentChargingSessions = currentChargingSessionsStored; - nextSessionIdxs = nextSessionIdxsStored; - } - - - @Override - public String toString() { - return "Power: " + getLastFlows().get(OL_EnergyCarriers.ELECTRICITY) + " kW, capacity: " + capacityElectric_kW + " kW" + - ", Active charging attitude " + this.chargingAttitude + - ", Smart charging capable: " + this.V1GCapable + - ", V2G capable: " + this.V2GCapable + - ", V2G active: " + this.V2GActive; - - } - - /** - * This number is here for model snapshot storing purpose
- * It needs to be changed when this class gets changed - */ - private static final long serialVersionUID = 1L; - -} +} \ No newline at end of file diff --git a/_alp/Classes/Class.J_EAChargePoint_OLD.java b/_alp/Classes/Class.J_EAChargePoint_OLD.java new file mode 100644 index 00000000..d879f5f5 --- /dev/null +++ b/_alp/Classes/Class.J_EAChargePoint_OLD.java @@ -0,0 +1,385 @@ +/** + * J_EAChargePoint + */ +public class J_EAChargePoint_OLD extends zero_engine.J_EA implements Serializable { + public double discharged_kWh; + public double charged_kWh; + public double capacityElectric_kW; + public List chargeSessionList; + private boolean V1GCapable; + private boolean V2GCapable; + private boolean V2GActive = false; + private int nbSockets; + private int[] nextSessionIdxs;// = 0; + + private J_ChargingSession[] currentChargingSessions; + + private int currentNumberOfChargingSockets = 0; // Used for certain charging algorithms + + // For filtered price + private double electricityPriceLowPassed_eurpkWh = 0.1; + private double priceFilterTimeScale_h = 5*24; + + // + private double dischargedStored_kWh; + private double chargedStored_kWh; + private J_ChargingSession[] currentChargingSessionsStored; + private int[] nextSessionIdxsStored; + + //Charging attitude + private OL_ChargingAttitude chargingAttitude = OL_ChargingAttitude.SIMPLE; + + /** + * Default constructor + */ + public J_EAChargePoint_OLD(Agent parentAgent, double electricCapacity_kW, double timestep_h, List chargeSessionList, boolean V1GCapable, boolean V2GCapable, int nbSockets) { + this.parentAgent = parentAgent; + this.capacityElectric_kW = electricCapacity_kW; + this.timestep_h = timestep_h; + this.chargeSessionList = chargeSessionList; + this.V1GCapable = V1GCapable; + this.V2GCapable = V2GCapable; + this.activeProductionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.ELECTRICITY); + if(V2GCapable && this.V2GActive) { + this.assetFlowCategory = OL_AssetFlowCategories.V2GPower_kW; + } else { + this.assetFlowCategory = OL_AssetFlowCategories.evChargingPower_kW; + } + this.nbSockets = nbSockets; + this.currentChargingSessions = new J_ChargingSession[nbSockets]; + this.nextSessionIdxs = new int[nbSockets]; + this.registerEnergyAsset(); + } + + public void f_updateAllFlows( double t_h) { + + double currentElectricityPriceConsumption_eurpkWh = ((GridConnection)parentAgent).energyModel.pp_dayAheadElectricityPricing_eurpMWh.getCurrentValue() * 0.001; + this.electricityPriceLowPassed_eurpkWh += (currentElectricityPriceConsumption_eurpkWh-electricityPriceLowPassed_eurpkWh) / (priceFilterTimeScale_h/timestep_h); + + /*if (gridAwareMode) { // Add gridload-factor to current price + currentElectricityPriceConsumption_eurpkWh = currentElectricityPriceConsumption_eurpkWh + (max(0,((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW-0.5))*0.1; + if ( ((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW > 0.5) { + //traceln("Adding %s eurpkWh to charging price to prevent congestion", (((GridConnection)parentAgent).p_parentNodeElectric.v_currentLoad_kW/((GridConnection)parentAgent).p_parentNodeElectric.p_capacity_kW-0.5)*1); + } + }*/ + + // Check if V2G is activated and the charger is capable + boolean doV2G = this.V2GActive && this.V2GCapable; + + // Update the J_ChargingSessions of the sockets + for (int i = 0; i= currentChargingSessions[i].startTime_h) { + power_kW += this.operateChargerSocket(i, t_h, currentElectricityPriceConsumption_eurpkWh, doV2G); + discharged_kWh += min(0,-power_kW) * timestep_h; + charged_kWh += max(0,power_kW) * timestep_h; + currentNumberOfChargingSockets++; + } + } + + // Call the regular J_EA updateAllFlows and operate + this.v_powerFraction_fr = power_kW / this.capacityElectric_kW; + super.f_updateAllFlows( ); + return; + } + + @Override + public void operate(double ratioOfCapacity) { + + double charge_kW = ratioOfCapacity * capacityElectric_kW; + + double electricityProduction_kW = max(-charge_kW, 0); + double electricityConsumption_kW = max(charge_kW, 0); + + energyUse_kW = electricityConsumption_kW - electricityProduction_kW; + energyUsed_kWh += energyUse_kW * timestep_h; + + flowsMap.put(OL_EnergyCarriers.ELECTRICITY, electricityConsumption_kW - electricityProduction_kW); + // Split charging and discharing power 'at the source'! + + if (charge_kW > 0) { // charging + assetFlowsMap.put(OL_AssetFlowCategories.evChargingPower_kW, electricityConsumption_kW); + } else if(charge_kW < 0){ + if(this.V2GCapable) { // && this.V2GActive) { + assetFlowsMap.put(OL_AssetFlowCategories.V2GPower_kW, electricityProduction_kW); + } + else { + traceln("Charge power in J_EAChargePoint negative: %s", charge_kW); + throw new RuntimeException("Trying to discharge into a charger, that does not have the capability or where v2g is not activated!"); + } + } + } + + + private double operateChargerSocket(int socketNb, double t_h, double currentElectricityPriceConsumption_eurpkWh, boolean doV2G) { + double chargeSetpoint_kW = 0; + if(!this.V1GCapable) { + chargeSetpoint_kW = determineChargeSetpoint_simple_kW(socketNb); + } + else { + switch(this.chargingAttitude) { + case SIMPLE: + chargeSetpoint_kW = determineChargeSetpoint_simple_kW(socketNb); + break; + case PRICE: + chargeSetpoint_kW = determineChargeSetpoint_price_kW(socketNb, t_h, doV2G, currentElectricityPriceConsumption_eurpkWh); + break; + case BALANCE_LOCAL: + throw new RuntimeException("BALANCE LOCAL CHARGING STRATEGY HAS NOT BEEN CREATED YET FOR CHARGEPOINTS"); + //chargeSetpoint_kW = determineChargeSetpoint_balanceLocal_kW(socketNb, t_h, doV2G); + case BALANCE_GRID: + chargeSetpoint_kW = determineChargeSetpoint_balanceGrid_kW(socketNb, t_h, doV2G); + break; + default: + throw new RuntimeException("UNSUPPORTED CHARGING ATTITUDE SELECTED FOR CHARGEPOINT"); + } + } + + return currentChargingSessions[socketNb].charge(chargeSetpoint_kW); + } + + + private double determineChargeSetpoint_simple_kW(int socketNb) { + double maxChargePower = capacityElectric_kW;//min(currentChargingSessions[socketNb].vehicleMaxChargingPower_kW, capacityElectric_kW); + double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! + double chargeSetpoint_kW = max(0, min(maxChargePower, remainingChargeDemand_kWh/timestep_h)); + + return chargeSetpoint_kW; + } + + private double determineChargeSetpoint_price_kW(int socketNb, double t_h, boolean doV2G, double currentElectricityPriceConsumption_eurpkWh) { + double maxChargePower = capacityElectric_kW;//min(currentChargingSessions[socketNb].vehicleMaxChargingPower_kW, capacityElectric_kW); + double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! + double chargeSetpoint_kW = 0; + + //traceln("Smart charging active at chargePoint"); + double nextTripStartTime_h = currentChargingSessions[socketNb].endTime_h; + double chargeTimeMargin_h = 0.5; // Margin to be ready with charging before start of next trip + double chargeDeadline_h = nextTripStartTime_h - remainingChargeDemand_kWh / maxChargePower - chargeTimeMargin_h; + double remainingFlexTime_h = chargeDeadline_h - t_h; // measure of flexiblity left in current charging session. + + if ( t_h >= chargeDeadline_h && remainingChargeDemand_kWh > 0) { // Must-charge time at max charging power + //traceln("Urgency charging on charge point GC: %s! May exceed connection capacity!", this.parentAgent); + chargeSetpoint_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); + } else { + double WTPoffset_eurpkW = 0.01; // Drops willingness to pay price for charging, combined with remainingFlexTime_h. + double WTPCharging_eurpkWh = electricityPriceLowPassed_eurpkWh - WTPoffset_eurpkW * remainingFlexTime_h; //+ urgencyGain_eurpkWh * ( max(0,maxSpreadChargingPower_kW) / ev.getCapacityElectric_kW() ); // Scale WTP based on flexibility expressed in terms of power-fraction + //WTPprice_eurpkWh = WTPoffset_eurpkWh + (main.v_epexNext24hours_eurpkWh+v_electricityPriceLowPassed_eurpkWh)/2 + flexibilityGain_eurpkWh * sqrt(maxSpreadChargingPower_kW/maxChargingPower_kW); + double priceGain_r = 0.5; // When WTP is higher than current electricity price, ramp up charging power with this gain based on the price-delta. + chargeSetpoint_kW = max(0, maxChargePower * min(1,(WTPCharging_eurpkWh / currentElectricityPriceConsumption_eurpkWh - 1) * priceGain_r)); // min(1,...) is needed to prevent devide by zero leading to infinity/NaN results. + if ( doV2G && remainingFlexTime_h > 1 && chargeSetpoint_kW == 0 ) { // Surpluss SOC and high energy price + //traceln("Conditions for V2G met in chargePoint"); + double V2G_WTS_offset_eurpkWh = 0.02; // Price must be at least this amount above the moving average to decide to discharge EV battery. + double WTSV2G_eurpkWh = V2G_WTS_offset_eurpkWh + electricityPriceLowPassed_eurpkWh; // Can become zero!! + chargeSetpoint_kW = min(0, -maxChargePower * min(1,(currentElectricityPriceConsumption_eurpkWh / WTSV2G_eurpkWh - 1) * priceGain_r)); // min(1,...) is needed to prevent devide by zero leading to infinity/NaN results. + //if (chargeSetpoint_kW < 0) {traceln(" V2G Active! Power: " + chargeSetpoint_kW );} + } + } + + return chargeSetpoint_kW; + } + + private double determineChargeSetpoint_balanceLocal_kW(int socketNb, double t_h, boolean doV2G) { + // DOES NOT MAKE SENSE TO USE THIS FOR GCPUBLIC CHARGER, ONLY FOR GC THAT HAVE THEIR OWN CONSUMPTION -> WHICH SHOULD BE SUPPORTED EVENTUALLY + if( parentAgent instanceof GCPublicCharger) { + throw new RuntimeException("This strategy only works for GCs that have their own consumption, do not use this for GCPublicChargers"); + } + + //CREATE STRATEGY HERE + double chargeSetpoint_kW = 0; + + return chargeSetpoint_kW; + } + + private double determineChargeSetpoint_balanceGrid_kW(int socketNb, double t_h, boolean doV2G) { + double chargeSetpoint_kW = 0; + double maxChargePower = capacityElectric_kW; + double remainingChargeDemand_kWh = currentChargingSessions[socketNb].getRemainingChargeDemand_kWh(); // Can be negative if recharging is not needed for next trip! + + GridNode parentNode = ((GridConnection)parentAgent).p_parentNodeElectric; + double currentBalanceOnGridNodeWithoutEV_kW = parentNode.v_currentLoad_kW - parentNode.v_currentChargingPower_kW; + double gridNodeLowPassedLoad_kW = parentNode.v_lowPassedLoadFilter_kW; + + double nextTripStartTime_h = currentChargingSessions[socketNb].endTime_h; + double chargeTimeMargin_h = 0.5; // Margin to be ready with charging before start of next trip + double chargeDeadline_h = nextTripStartTime_h - remainingChargeDemand_kWh / maxChargePower - chargeTimeMargin_h; + double remainingFlexTime_h = chargeDeadline_h - t_h; // measure of flexiblity left in current charging session. + double remainingTimeToCharge = nextTripStartTime_h - t_h - chargeTimeMargin_h; + + /*double avgPowerDemandTillTrip_kW = 0; + if(remainingTimeToCharge != 0) { + avgPowerDemandTillTrip_kW = remainingChargeDemand_kWh / (nextTripStartTime_h - t_h - chargeTimeMargin_h); + } + else if(remainingChargeDemand_kWh > 0) { + avgPowerDemandTillTrip_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); + }*/ + + if ( t_h >= chargeDeadline_h && remainingChargeDemand_kWh > 0) { // Must-charge time at max charging power + chargeSetpoint_kW = min(maxChargePower, remainingChargeDemand_kWh/timestep_h); + } else { + double flexGain_r_manual = 0.8; + double flexGain_r = 1/max(1, (double)parentNode.v_currentNumberOfChargingChargePoints) * flexGain_r_manual; // how strongly to 'follow' currentBalanceBeforeEV_kW -> influenced by the amount of charging chargers at this momment + chargeSetpoint_kW = max(0, currentChargingSessions[socketNb].avgPowerDemand_kW + (gridNodeLowPassedLoad_kW - currentBalanceOnGridNodeWithoutEV_kW) * (min(1,flexGain_r))); + if ( doV2G && remainingFlexTime_h > 1 && chargeSetpoint_kW == 0 ) { // Surpluss flexibility + chargeSetpoint_kW = min(0, currentChargingSessions[socketNb].avgPowerDemand_kW + (gridNodeLowPassedLoad_kW - currentBalanceOnGridNodeWithoutEV_kW) * (min(1,flexGain_r))); + } + } + return chargeSetpoint_kW; + } + + + + private void manageSocket(int socketNb, double t_h) { + if (this.currentChargingSessions[socketNb] != null && t_h >= this.currentChargingSessions[socketNb].endTime_h) { // end session + if (this.currentChargingSessions[socketNb].getRemainingChargeDemand_kWh() > 0.001 ) { traceln("!!Chargesession ended but charge demand not fullfilled!! Remaining demand: %s kWh", this.currentChargingSessions[socketNb].getRemainingChargeDemand_kWh()); } + this.currentChargingSessions[socketNb] = null; + } + + + if ( this.currentChargingSessions[socketNb] == null ) { // socket currently free + // check if we are not already past the last charging session. + // Find next charging session on this socket + + while (this.nextSessionIdxs[socketNb] < this.chargeSessionList.size() && this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).socketNb != socketNb) { + this.nextSessionIdxs[socketNb]++; + } + + if (this.nextSessionIdxs[socketNb] >= this.chargeSessionList.size()) { // no more sessions available + //traceln("Reached end of charging session list!"); + return; + } else { + this.currentChargingSessions[socketNb] = this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).getClone(); + + if (t_h > this.currentChargingSessions[socketNb].startTime_h) { + traceln("Chargesession %s started %s hours too late!", this.nextSessionIdxs[socketNb], t_h - this.currentChargingSessions[socketNb].startTime_h); + if (t_h >= this.currentChargingSessions[socketNb].endTime_h) { + traceln("!!Chargesession started after its endTime_h!! WTF?"); + } + } + this.nextSessionIdxs[socketNb]++; + } + } + } + + + public void fastForwardCharingSessions(double t_h) { + for (int socketNb = 0; socketNb= this.chargeSessionList.size()) { // no more sessions available + break; + } else { // Clone upcomming charger session and increase next session index + this.currentChargingSessions[socketNb] = this.chargeSessionList.get(this.nextSessionIdxs[socketNb]).getClone(); + this.nextSessionIdxs[socketNb]++; + } + } + } + + + public void setV1GCapability(boolean V1GCapable) { + this.V1GCapable = V1GCapable; + } + public void setV2GCapability(boolean V2GCapable) { + this.V2GCapable = V2GCapable; + this.updateAssetFlowCategory(); + } + public boolean getV1GCapable() { + return this.V1GCapable; + + } + public boolean getV2GCapable() { + return this.V2GCapable; + + } + + public void setChargingAttitude(OL_ChargingAttitude chargingAttitude) { + this.chargingAttitude = chargingAttitude; + } + + public OL_ChargingAttitude getChargingAttitude() { + return this.chargingAttitude; + } + + public void setV2GActive(boolean activateV2G) { + this.V2GActive = activateV2G; + this.updateAssetFlowCategory(); + } + + public boolean getV2GActive() { + return this.V2GActive; + } + + private void updateAssetFlowCategory() { + if(this.V2GCapable && this.V2GActive) { + this.assetFlowCategory = OL_AssetFlowCategories.V2GPower_kW; + } + else { + this.assetFlowCategory = OL_AssetFlowCategories.evChargingPower_kW; + } + } + + public int getCurrentNumberOfChargingSockets() { + return this.currentNumberOfChargingSockets; + } + + @Override + public void storeStatesAndReset() { + energyUsedStored_kWh = energyUsed_kWh; + energyUsed_kWh = 0.0; + dischargedStored_kWh = discharged_kWh; + discharged_kWh = 0.0; + chargedStored_kWh = charged_kWh; + charged_kWh = 0.0; + + currentChargingSessionsStored = currentChargingSessions.clone(); + Arrays.fill(currentChargingSessions, null); + + nextSessionIdxsStored = nextSessionIdxs; + nextSessionIdxs = new int[nextSessionIdxsStored.length]; + + clear(); + } + + @Override + public void restoreStates() { + energyUsed_kWh = energyUsedStored_kWh; + discharged_kWh = dischargedStored_kWh; + charged_kWh = chargedStored_kWh; + + currentChargingSessions = currentChargingSessionsStored; + nextSessionIdxs = nextSessionIdxsStored; + } + + + @Override + public String toString() { + return "Power: " + getLastFlows().get(OL_EnergyCarriers.ELECTRICITY) + " kW, capacity: " + capacityElectric_kW + " kW" + + ", Active charging attitude " + this.chargingAttitude + + ", Smart charging capable: " + this.V1GCapable + + ", V2G capable: " + this.V2GCapable + + ", V2G active: " + this.V2GActive; + + } + + /** + * This number is here for model snapshot storing purpose
+ * It needs to be changed when this class gets changed + */ + private static final long serialVersionUID = 1L; + +} From 025d5b5fc9a58ffd6f3043c16bff9b59f9ecbf4d Mon Sep 17 00:00:00 2001 From: Ate Hempenius Date: Fri, 5 Dec 2025 10:16:46 +0100 Subject: [PATCH 02/12] time data, in progress --- Zero_engine.alpx | 5 + _alp/Agents/EnergyModel/Code/Functions.java | 11 +- _alp/Classes/Class.J_EAChargePoint.java | 23 ++- _alp/Classes/Class.J_TimeData.java | 153 ++++++++++++++++++++ 4 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 _alp/Classes/Class.J_TimeData.java diff --git a/Zero_engine.alpx b/Zero_engine.alpx index 4e5f85b6..7f088509 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1803,6 +1803,11 @@ 1752677832758 + + 1764858648960 + + 1752680962144 + com.anylogic.libraries.modules.markup_descriptors diff --git a/_alp/Agents/EnergyModel/Code/Functions.java b/_alp/Agents/EnergyModel/Code/Functions.java index 6ac75f6c..75301fe1 100644 --- a/_alp/Agents/EnergyModel/Code/Functions.java +++ b/_alp/Agents/EnergyModel/Code/Functions.java @@ -35,13 +35,6 @@ double f_updateTimeseries(double t_h) {/*ALCODESTART::1664952601107*/ -b_isDaytime = t_h % 24 > 6 && t_h % 24 < 18; -b_isWeekday = (t_h+(v_dayOfWeek1jan-1)*24) % (24*7) < (24*5); -b_isSummerWeek = (t_h % 8760) >= p_startOfSummerWeek_h && (t_h % 8760) < p_startOfSummerWeek_h + 24*7; -b_isWinterWeek = (t_h % 8760) >= p_startOfWinterWeek_h && (t_h % 8760) < p_startOfWinterWeek_h + 24*7; -b_isLastTimeStepOfDay = t_h % 24 == (24-p_timeStep_h); -t_hourOfDay = t_h % 24; // Assumes modelrun starts at midnight. - c_profiles.forEach(p -> p.updateValue(t_h)); //v_currentAmbientTemperature_degC = pp_ambientTemperature_degC.getCurrentValue(); //v_currentWindPowerNormalized_r = pp_windProduction_fr.getCurrentValue(); @@ -475,8 +468,8 @@ f_loopSimulation(); } -//Update t_h -t_h = p_runStartTime_h + v_timeStepsElapsed * p_timeStep_h; +//Update time variables +J_TimeData.updateTimeVariables(v_timeStepsElapsed); // Update tijdreeksen in leesbare variabelen f_updateTimeseries(t_h); diff --git a/_alp/Classes/Class.J_EAChargePoint.java b/_alp/Classes/Class.J_EAChargePoint.java index fec84388..31878584 100644 --- a/_alp/Classes/Class.J_EAChargePoint.java +++ b/_alp/Classes/Class.J_EAChargePoint.java @@ -107,9 +107,9 @@ public void f_updateAllFlows(double chargePower_kW) { public void operate(double chargePower_kW) { flowsMap.put(OL_EnergyCarriers.ELECTRICITY, chargePower_kW); // Split charging and discharing power 'at the source'! - assetFlowsMap.put(OL_AssetFlowCategories.evChargingPower_kW, this.totalChargePower_kW); + assetFlowsMap.put(OL_AssetFlowCategories.evChargingPower_kW, this.currentChargePower_kW); if (this.V2GCapable && this.V2GActive) { - assetFlowsMap.put(OL_AssetFlowCategories.V2GPower_kW, this.totalDischargePower_kW); + assetFlowsMap.put(OL_AssetFlowCategories.V2GPower_kW, this.currentDischargePower_kW); } } @@ -143,6 +143,25 @@ public void addChargingRequest( I_ChargingRequest chargingRequest ) { this.currentActiveChargingRequests.add(chargingRequest); } + + + //V1G and V2G capabilities setters/getters + public void setV1GCapability(boolean V1GCapable) { + this.V1GCapable = V1GCapable; + } + public void setV2GCapability(boolean V2GCapable) { + this.V2GCapable = V2GCapable; + this.updateAssetFlowCategory(); + } + public boolean getV1GCapable() { + return this.V1GCapable; + + } + public boolean getV2GCapable() { + return this.V2GCapable; + + } + @Override public void storeStatesAndReset() { // TODO: Finish this !! diff --git a/_alp/Classes/Class.J_TimeData.java b/_alp/Classes/Class.J_TimeData.java new file mode 100644 index 00000000..b5dbb77f --- /dev/null +++ b/_alp/Classes/Class.J_TimeData.java @@ -0,0 +1,153 @@ +/** + * J_TimeData + */ +public class J_TimeData { + //Time parameters: + private static double timeStep_h = 0.25; + + private static int startYear = 2024; + private static double[] hourOfYearPerMonth; + private static int dayOfWeek1jan; + + private static double runStartTime_h; + private static double runEndTime_h; + + private static int winterWeekNumber; + private static int summerWeekNumber; + private static double startOfSummerWeek_h; + private static double startOfWinterWeek_h; + + public static double getTimeStep_h() { + return timeStep_h; + } + + public static void setTimeStep_h(double timeStep_h) { + timeStep_h = timeStep_h; + } + + public static int getStartYear() { + return startYear; + } + + public static void setStartYear(int startYear) { + startYear = startYear; + } + + public static double[] getHourOfYearPerMonth() { + return hourOfYearPerMonth; + } + + public static void setHourOfYearPerMonth(double[] hourOfYearPerMonth) { + hourOfYearPerMonth = hourOfYearPerMonth; + } + + public static int getDayOfWeek1jan() { + return dayOfWeek1jan; + } + + public static void setDayOfWeek1jan(int dayOfWeek1jan) { + dayOfWeek1jan = dayOfWeek1jan; + } + + public static double getRunStartTime_h() { + return runStartTime_h; + } + + public static void setRunStartTime_h(double runStartTime_h) { + runStartTime_h = runStartTime_h; + } + + public static double getRunEndTime_h() { + return runEndTime_h; + } + + public static void setRunEndTime_h(double runEndTime_h) { + runEndTime_h = runEndTime_h; + } + + public static int getWinterWeekNumber() { + return winterWeekNumber; + } + + public static void setWinterWeekNumber(int winterWeekNumber) { + winterWeekNumber = winterWeekNumber; + } + + public static int getSummerWeekNumber() { + return summerWeekNumber; + } + + public static void setSummerWeekNumber(int summerWeekNumber) { + summerWeekNumber = summerWeekNumber; + } + + public static double getStartOfSummerWeek_h() { + return startOfSummerWeek_h; + } + + public static void setStartOfSummerWeek_h(double startOfSummerWeek_h) { + startOfSummerWeek_h = startOfSummerWeek_h; + } + + public static double getStartOfWinterWeek_h() { + return startOfWinterWeek_h; + } + + public static void setStartOfWinterWeek_h(double startOfWinterWeek_h) { + startOfWinterWeek_h = startOfWinterWeek_h; + } + + //Time Variables + private static double t_h = 0; //Current energymodel runtime: t_h = 0, corresponds to 'jan 1 0:00' of the start year + private static double t_hourOfDay = 0; + private static double timeStepsElapsed = 0; + + private static boolean isDaytime = false; + private static boolean isWeekday = false; + private static boolean isSummerWeek = false; + private static boolean isWinterWeek = false; + private static boolean isLastTimeStepOfDay = false; + + public static void updateTimeVariables(int v_timeStepsElapsed) { + timeStepsElapsed = v_timeStepsElapsed; + t_h = runStartTime_h + timeStepsElapsed * timeStep_h; + isDaytime = t_h % 24 > 6 && t_h % 24 < 18; + isWeekday = (t_h+(dayOfWeek1jan-1)*24) % (24*7) < (24*5); + isSummerWeek = (t_h % 8760) >= startOfSummerWeek_h && (t_h % 8760) < startOfSummerWeek_h + 24*7; + isWinterWeek = (t_h % 8760) >= startOfWinterWeek_h && (t_h % 8760) < startOfWinterWeek_h + 24*7; + isLastTimeStepOfDay = t_h % 24 == (24-timeStep_h); + t_hourOfDay = t_h % 24; // Assumes modelrun starts at midnight. + } + + public static double getT_h() { + return t_h; + } + + public static double getT_hourOfDay() { + return t_hourOfDay; + } + + public static double getTimeStepsElapsed() { + return timeStepsElapsed; + } + + public static boolean isDaytime() { + return isDaytime; + } + + public static boolean isWeekday() { + return isWeekday; + } + + public static boolean isSummerWeek() { + return isSummerWeek; + } + + public static boolean isWinterWeek() { + return isWinterWeek; + } + + public static boolean isLastTimeStepOfDay() { + return isLastTimeStepOfDay; + } +} \ No newline at end of file From 0e549ffbd5ad3a7c9903919c0d631d929a59bcc7 Mon Sep 17 00:00:00 2001 From: Ate Hempenius Date: Fri, 5 Dec 2025 15:00:25 +0100 Subject: [PATCH 03/12] timedata split in two: parameters and variables --- Zero_engine.alpx | 18 +- _alp/Agents/EnergyModel/Code/Functions.java | 2 +- _alp/Classes/Class.J_EAChargePoint.java | 10 +- _alp/Classes/Class.J_TimeData.java | 153 ----------------- _alp/Classes/Class.J_TimeParameters.java | 172 ++++++++++++++++++++ _alp/Classes/Class.J_TimeVariables.java | 67 ++++++++ 6 files changed, 263 insertions(+), 159 deletions(-) delete mode 100644 _alp/Classes/Class.J_TimeData.java create mode 100644 _alp/Classes/Class.J_TimeParameters.java create mode 100644 _alp/Classes/Class.J_TimeVariables.java diff --git a/Zero_engine.alpx b/Zero_engine.alpx index 190961d3..acab56a6 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1152,6 +1152,11 @@ 1762850958928 + + 1764938574089 + + 1752680962144 + EULER @@ -1791,7 +1796,7 @@ 1763570262548 - 1752680962144 + 1764938574089 1764337491572 @@ -1804,9 +1809,14 @@ 1752677832758 - 1764858648960 - - 1752680962144 + 1764936717326 + + 1764938574089 + + + 1764936749914 + + 1764938574089 diff --git a/_alp/Agents/EnergyModel/Code/Functions.java b/_alp/Agents/EnergyModel/Code/Functions.java index 75301fe1..41a63994 100644 --- a/_alp/Agents/EnergyModel/Code/Functions.java +++ b/_alp/Agents/EnergyModel/Code/Functions.java @@ -469,7 +469,7 @@ } //Update time variables -J_TimeData.updateTimeVariables(v_timeStepsElapsed); +J_TimeVariables.updateTimeVariables(v_timeStepsElapsed); // Update tijdreeksen in leesbare variabelen f_updateTimeseries(t_h); diff --git a/_alp/Classes/Class.J_EAChargePoint.java b/_alp/Classes/Class.J_EAChargePoint.java index 31878584..0c691b19 100644 --- a/_alp/Classes/Class.J_EAChargePoint.java +++ b/_alp/Classes/Class.J_EAChargePoint.java @@ -119,7 +119,7 @@ public void updateActiveChargingRequests() { List finishedChargingRequests = new ArrayList<>(); for (I_ChargingRequest chargingRequest : this.currentActiveChargingRequests) { // here we will use the soon to be global parameter current time - if ( t_h >= chargingRequest.getLeaveTime_h() ) { + if ( J_TimeVariables.getT_h() >= chargingRequest.getLeaveTime_h() ) { finishedChargingRequests.add(chargingRequest); } } @@ -161,6 +161,14 @@ public boolean getV2GCapable() { return this.V2GCapable; } + public void setV2GActive(boolean activateV2G) { + this.V2GActive = activateV2G; + this.updateAssetFlowCategory(); + } + + public boolean getV2GActive() { + return this.V2GActive; + } @Override public void storeStatesAndReset() { diff --git a/_alp/Classes/Class.J_TimeData.java b/_alp/Classes/Class.J_TimeData.java deleted file mode 100644 index b5dbb77f..00000000 --- a/_alp/Classes/Class.J_TimeData.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * J_TimeData - */ -public class J_TimeData { - //Time parameters: - private static double timeStep_h = 0.25; - - private static int startYear = 2024; - private static double[] hourOfYearPerMonth; - private static int dayOfWeek1jan; - - private static double runStartTime_h; - private static double runEndTime_h; - - private static int winterWeekNumber; - private static int summerWeekNumber; - private static double startOfSummerWeek_h; - private static double startOfWinterWeek_h; - - public static double getTimeStep_h() { - return timeStep_h; - } - - public static void setTimeStep_h(double timeStep_h) { - timeStep_h = timeStep_h; - } - - public static int getStartYear() { - return startYear; - } - - public static void setStartYear(int startYear) { - startYear = startYear; - } - - public static double[] getHourOfYearPerMonth() { - return hourOfYearPerMonth; - } - - public static void setHourOfYearPerMonth(double[] hourOfYearPerMonth) { - hourOfYearPerMonth = hourOfYearPerMonth; - } - - public static int getDayOfWeek1jan() { - return dayOfWeek1jan; - } - - public static void setDayOfWeek1jan(int dayOfWeek1jan) { - dayOfWeek1jan = dayOfWeek1jan; - } - - public static double getRunStartTime_h() { - return runStartTime_h; - } - - public static void setRunStartTime_h(double runStartTime_h) { - runStartTime_h = runStartTime_h; - } - - public static double getRunEndTime_h() { - return runEndTime_h; - } - - public static void setRunEndTime_h(double runEndTime_h) { - runEndTime_h = runEndTime_h; - } - - public static int getWinterWeekNumber() { - return winterWeekNumber; - } - - public static void setWinterWeekNumber(int winterWeekNumber) { - winterWeekNumber = winterWeekNumber; - } - - public static int getSummerWeekNumber() { - return summerWeekNumber; - } - - public static void setSummerWeekNumber(int summerWeekNumber) { - summerWeekNumber = summerWeekNumber; - } - - public static double getStartOfSummerWeek_h() { - return startOfSummerWeek_h; - } - - public static void setStartOfSummerWeek_h(double startOfSummerWeek_h) { - startOfSummerWeek_h = startOfSummerWeek_h; - } - - public static double getStartOfWinterWeek_h() { - return startOfWinterWeek_h; - } - - public static void setStartOfWinterWeek_h(double startOfWinterWeek_h) { - startOfWinterWeek_h = startOfWinterWeek_h; - } - - //Time Variables - private static double t_h = 0; //Current energymodel runtime: t_h = 0, corresponds to 'jan 1 0:00' of the start year - private static double t_hourOfDay = 0; - private static double timeStepsElapsed = 0; - - private static boolean isDaytime = false; - private static boolean isWeekday = false; - private static boolean isSummerWeek = false; - private static boolean isWinterWeek = false; - private static boolean isLastTimeStepOfDay = false; - - public static void updateTimeVariables(int v_timeStepsElapsed) { - timeStepsElapsed = v_timeStepsElapsed; - t_h = runStartTime_h + timeStepsElapsed * timeStep_h; - isDaytime = t_h % 24 > 6 && t_h % 24 < 18; - isWeekday = (t_h+(dayOfWeek1jan-1)*24) % (24*7) < (24*5); - isSummerWeek = (t_h % 8760) >= startOfSummerWeek_h && (t_h % 8760) < startOfSummerWeek_h + 24*7; - isWinterWeek = (t_h % 8760) >= startOfWinterWeek_h && (t_h % 8760) < startOfWinterWeek_h + 24*7; - isLastTimeStepOfDay = t_h % 24 == (24-timeStep_h); - t_hourOfDay = t_h % 24; // Assumes modelrun starts at midnight. - } - - public static double getT_h() { - return t_h; - } - - public static double getT_hourOfDay() { - return t_hourOfDay; - } - - public static double getTimeStepsElapsed() { - return timeStepsElapsed; - } - - public static boolean isDaytime() { - return isDaytime; - } - - public static boolean isWeekday() { - return isWeekday; - } - - public static boolean isSummerWeek() { - return isSummerWeek; - } - - public static boolean isWinterWeek() { - return isWinterWeek; - } - - public static boolean isLastTimeStepOfDay() { - return isLastTimeStepOfDay; - } -} \ No newline at end of file diff --git a/_alp/Classes/Class.J_TimeParameters.java b/_alp/Classes/Class.J_TimeParameters.java new file mode 100644 index 00000000..1d48b4f6 --- /dev/null +++ b/_alp/Classes/Class.J_TimeParameters.java @@ -0,0 +1,172 @@ +/** + * J_TimeParameters + */ +public class J_TimeParameters { + ////Time parameters: + private static double timeStep_h = 0.25; + + private static int startYear = 2024; + private static double[] hourOfYearPerMonth; + private static int dayOfWeek1jan; + + private static double runStartTime_h; + private static double runEndTime_h; + + private static int winterWeekNumber; + private static int summerWeekNumber; + private static double startOfSummerWeek_h; + private static double startOfWinterWeek_h; + + //IsFinal booleans used to make the parameters artificially final + private static boolean timeStep_hIsFinal = false; + + private static boolean startYearIsFinal = false; + private static boolean hourOfYearPerMonthIsFinal = false; + private static boolean dayOfWeek1janIsFinal = false; + + private static boolean runStartTime_hIsFinal = false; + private static boolean runEndTime_hIsFinal = false; + + private static boolean winterWeekNumberIsFinal = false; + private static boolean summerWeekNumberIsFinal = false; + private static boolean startOfSummerWeek_hIsFinal = false; + private static boolean startOfWinterWeek_hIsFinal = false; + + ////Time parameter setters: Can only be called once, after that they are made final. + public static void setTimeStep_h(double p_timeStep_h) { + if(!timeStep_hIsFinal) { + timeStep_h = p_timeStep_h; + timeStep_hIsFinal = true; + } + else { + throw new RuntimeException("Trying to set timeStep_h while it is final!"); + } + } + public static void setStartYear(int p_startYear) { + if(!startYearIsFinal) { + startYear = p_startYear; + startYearIsFinal = true; + } + else { + throw new RuntimeException("Trying to set startYear while it is final!"); + } + } + public static void setHourOfYearPerMonth(double[] p_hourOfYearPerMonth) { + if(!hourOfYearPerMonthIsFinal) { + hourOfYearPerMonth = p_hourOfYearPerMonth; + hourOfYearPerMonthIsFinal = true; + } + else { + throw new RuntimeException("Trying to set hourOfYearPerMonth while it is final!"); + } + } + public static void setDayOfWeek1jan(int p_dayOfWeek1jan) { + if(!dayOfWeek1janIsFinal) { + dayOfWeek1jan = p_dayOfWeek1jan; + dayOfWeek1janIsFinal = true; + } + else { + throw new RuntimeException("Trying to set dayOfWeek1jan while it is final!"); + } + } + public static void setRunStartTime_h(double p_runStartTime_h) { + if(!runStartTime_hIsFinal) { + runStartTime_h = p_runStartTime_h; + runStartTime_hIsFinal = true; + } + else { + throw new RuntimeException("Trying to set runStartTime_h while it is final!"); + } + } + public static void setRunEndTime_h(double p_runEndTime_h) { + if(!runEndTime_hIsFinal) { + runEndTime_h = p_runEndTime_h; + runEndTime_hIsFinal = true; + } + else { + throw new RuntimeException("Trying to set runEndTime_h while it is final!"); + } + } + public static void setWinterWeekNumber(int p_winterWeekNumber) { + if(!winterWeekNumberIsFinal) { + winterWeekNumber = p_winterWeekNumber; + winterWeekNumberIsFinal = true; + } + else { + throw new RuntimeException("Trying to set winterWeekNumber while it is final!"); + } + } + public static void setSummerWeekNumber(int p_summerWeekNumber) { + if(!summerWeekNumberIsFinal) { + summerWeekNumber = p_summerWeekNumber; + summerWeekNumberIsFinal = true; + } + else { + throw new RuntimeException("Trying to set summerWeekNumber while it is final!"); + } + } + public static void setStartOfSummerWeek_h(double p_startOfSummerWeek_h) { + if(!startOfSummerWeek_hIsFinal) { + startOfSummerWeek_h = p_startOfSummerWeek_h; + startOfSummerWeek_hIsFinal = true; + } + else { + throw new RuntimeException("Trying to set startOfSummerWeek_h while it is final!"); + } + } + public static void setStartOfWinterWeek_h(double p_startOfWinterWeek_h) { + if(!startOfWinterWeek_hIsFinal) { + startOfWinterWeek_h = p_startOfWinterWeek_h; + startOfWinterWeek_hIsFinal = true; + } + else { + throw new RuntimeException("Trying to set startOfWinterWeek_h while it is final!"); + } + } + + ////Finalize all current values of Time parameters -> After this they can't be adjusted anymore. + public static void finalizeTimeParameters() { + timeStep_hIsFinal = true; + startYearIsFinal = true; + hourOfYearPerMonthIsFinal = true; + dayOfWeek1janIsFinal = true; + runStartTime_hIsFinal = true; + runEndTime_hIsFinal = true; + winterWeekNumberIsFinal = true; + summerWeekNumberIsFinal = true; + startOfSummerWeek_hIsFinal = true; + startOfWinterWeek_hIsFinal = true; + } + + ////Time Parameter getters + public static double getTimeStep_h() { + return timeStep_h; + } + public static int getStartYear() { + return startYear; + } + public static double[] getHourOfYearPerMonth() { + return hourOfYearPerMonth; + } + public static int getDayOfWeek1jan() { + return dayOfWeek1jan; + } + public static double getRunStartTime_h() { + return runStartTime_h; + } + public static double getRunEndTime_h() { + return runEndTime_h; + } + public static int getWinterWeekNumber() { + return winterWeekNumber; + } + public static int getSummerWeekNumber() { + return summerWeekNumber; + } + public static double getStartOfSummerWeek_h() { + return startOfSummerWeek_h; + } + public static double getStartOfWinterWeek_h() { + return startOfWinterWeek_h; + } +} \ No newline at end of file diff --git a/_alp/Classes/Class.J_TimeVariables.java b/_alp/Classes/Class.J_TimeVariables.java new file mode 100644 index 00000000..615c1c5e --- /dev/null +++ b/_alp/Classes/Class.J_TimeVariables.java @@ -0,0 +1,67 @@ +/** + * J_TimeVariables + */ +public class J_TimeVariables { + ////Time Variables -> Updated every timestep + private static double t_h = 0; //Current energymodel runtime: t_h = 0, corresponds to 'jan 1 0:00' of the start year + private static double t_hourOfDay = 0; + private static double timeStepsElapsed = 0; + + private static boolean isDaytime = false; + private static boolean isWeekday = false; + private static boolean isSummerWeek = false; + private static boolean isWinterWeek = false; + private static boolean isLastTimeStepOfDay = false; + + public static void updateTimeVariables(int v_timeStepsElapsed) { + timeStepsElapsed = v_timeStepsElapsed; + t_h = J_TimeParameters.getRunStartTime_h() + timeStepsElapsed * J_TimeParameters.getTimeStep_h(); + isDaytime = t_h % 24 > 6 && t_h % 24 < 18; + isWeekday = (t_h+(J_TimeParameters.getDayOfWeek1jan()-1)*24) % (24*7) < (24*5); + isSummerWeek = (t_h % 8760) >= J_TimeParameters.getStartOfSummerWeek_h() && (t_h % 8760) < J_TimeParameters.getStartOfSummerWeek_h() + 24*7; + isWinterWeek = (t_h % 8760) >= J_TimeParameters.getStartOfWinterWeek_h() && (t_h % 8760) < J_TimeParameters.getStartOfWinterWeek_h() + 24*7; + isLastTimeStepOfDay = t_h % 24 == (24-J_TimeParameters.getTimeStep_h()); + t_hourOfDay = t_h % 24; // Assumes modelrun starts at midnight. + } + + public static double getT_h() { + return t_h; + } + + public static double getT_hourOfDay() { + return t_hourOfDay; + } + + public static double getTimeStepsElapsed() { + return timeStepsElapsed; + } + + public static boolean isDaytime() { + return isDaytime; + } + + public static boolean isWeekday() { + return isWeekday; + } + + public static boolean isSummerWeek() { + return isSummerWeek; + } + + public static boolean isWinterWeek() { + return isWinterWeek; + } + + public static boolean isLastTimeStepOfDay() { + return isLastTimeStepOfDay; + } + + public static Date getDate(Experiment experiment) { + Date startDate = experiment.getEngine().getStartDate(); + long startDateUnixTime_ms = startDate.getTime(); + long runtime_ms = (long) (timeStepsElapsed * J_TimeParameters.getTimeStep_h() * 60 * 60 * 1000); + Date date = new Date(); + date.setTime(startDateUnixTime_ms + runtime_ms); + return date; + } +} \ No newline at end of file From 8e3964fae4016fe7c78b23835a2af559dee164b8 Mon Sep 17 00:00:00 2001 From: Ate Hempenius Date: Mon, 8 Dec 2025 13:19:15 +0100 Subject: [PATCH 04/12] J_ChargingSession -> J_EAChargingSession. interface implemented for EV and J_EAChargingSession. time variables/parameters no longer globals -> Will also be different pull request. IN PROGRESS --- Zero_engine.alpx | 10 +- _alp/Agents/EnergyModel/Code/Functions.java | 10 ++ _alp/Agents/EnergyModel/Variables.xml | 58 ++++++- .../Agents/GridConnection/Code/Functions.java | 10 -- _alp/Agents/GridNode/Code/Functions.java | 4 +- _alp/Agents/GridNode/Variables.xml | 2 +- _alp/Classes/Class.I_ChargingRequest.java | 4 +- .../Classes/Class.J_ActivityTrackerTrips.java | 6 +- ...ss.J_ChargingManagementLocalBalancing.java | 6 +- ...J_ChargingManagementMaxAvailablePower.java | 8 +- .../Class.J_ChargingManagementOffPeak.java | 10 +- .../Class.J_ChargingManagementPrice.java | 10 +- _alp/Classes/Class.J_EAChargePoint.java | 62 +++++-- _alp/Classes/Class.J_EAChargingSession.java | 151 ++++++++++++++++++ _alp/Classes/Class.J_EAEV.java | 30 ++-- _alp/Classes/Class.J_EAVehicle.java | 4 +- 16 files changed, 324 insertions(+), 61 deletions(-) create mode 100644 _alp/Classes/Class.J_EAChargingSession.java diff --git a/Zero_engine.alpx b/Zero_engine.alpx index acab56a6..90202ad3 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1533,6 +1533,7 @@ 1749649002419 + true 1752680962144 @@ -1811,12 +1812,17 @@ 1764936717326 - 1764938574089 + 1752680962144 1764936749914 - 1764938574089 + 1752680962144 + + + 1765192207409 + + 1752677832758 diff --git a/_alp/Agents/EnergyModel/Code/Functions.java b/_alp/Agents/EnergyModel/Code/Functions.java index 41a63994..60269d6f 100644 --- a/_alp/Agents/EnergyModel/Code/Functions.java +++ b/_alp/Agents/EnergyModel/Code/Functions.java @@ -35,6 +35,13 @@ double f_updateTimeseries(double t_h) {/*ALCODESTART::1664952601107*/ +b_isDaytime = t_h % 24 > 6 && t_h % 24 < 18; +b_isWeekday = (t_h+(v_dayOfWeek1jan-1)*24) % (24*7) < (24*5); +b_isSummerWeek = (t_h % 8760) >= p_startOfSummerWeek_h && (t_h % 8760) < p_startOfSummerWeek_h + 24*7; +b_isWinterWeek = (t_h % 8760) >= p_startOfWinterWeek_h && (t_h % 8760) < p_startOfWinterWeek_h + 24*7; +b_isLastTimeStepOfDay = t_h % 24 == (24-p_timeStep_h); +t_hourOfDay = t_h % 24; // Assumes modelrun starts at midnight. + c_profiles.forEach(p -> p.updateValue(t_h)); //v_currentAmbientTemperature_degC = pp_ambientTemperature_degC.getCurrentValue(); //v_currentWindPowerNormalized_r = pp_windProduction_fr.getCurrentValue(); @@ -468,6 +475,9 @@ f_loopSimulation(); } +//Update t_h +t_h = p_runStartTime_h + v_timeStepsElapsed * p_timeStep_h; + //Update time variables J_TimeVariables.updateTimeVariables(v_timeStepsElapsed); diff --git a/_alp/Agents/EnergyModel/Variables.xml b/_alp/Agents/EnergyModel/Variables.xml index 62419e43..c19ea471 100644 --- a/_alp/Agents/EnergyModel/Variables.xml +++ b/_alp/Agents/EnergyModel/Variables.xml @@ -1960,6 +1960,62 @@
+ + 1765189970308 + + -610 + 330 + + false + true + true + + + NONE + false + + + + + 1765189970306 + TEXT_BOX + 0 + 100 + NO_DELIMETER + + + + + 1765189991043 + + -610 + 310 + + false + true + true + + + NONE + false + + + + + 1765189991041 + TEXT_BOX + 0 + 100 + NO_DELIMETER + + + 1663238323139 @@ -2284,7 +2340,7 @@ true ArrayList - List<J_ChargingSession> + List<J_EAChargingSession> String diff --git a/_alp/Agents/GridConnection/Code/Functions.java b/_alp/Agents/GridConnection/Code/Functions.java index 9ac664ae..a4266de8 100644 --- a/_alp/Agents/GridConnection/Code/Functions.java +++ b/_alp/Agents/GridConnection/Code/Functions.java @@ -1428,16 +1428,6 @@ EnergyCoop f_addAssetFlow(OL_AssetFlowCategories AC) p_chargingManagement = chargingManagement; -//TEMPORARY UNTIL CHARGEPOINT MANAGEMENT AND EV CHARGING MANAGEMENT ARE COMBINED -if (c_chargers.size()>0){ - if (chargingType == null) { - throw new RuntimeException("Charging strategy needed when chargers are present!"); - } - else{ - c_chargers.forEach(charger -> charger.setChargingAttitude(chargingType)); - } -} - //Add new asset management to energyModel if(this.p_chargingManagement != null){ energyModel.f_registerAssetManagement(this.p_chargingManagement); diff --git a/_alp/Agents/GridNode/Code/Functions.java b/_alp/Agents/GridNode/Code/Functions.java index 7ca6da18..d046047e 100644 --- a/_alp/Agents/GridNode/Code/Functions.java +++ b/_alp/Agents/GridNode/Code/Functions.java @@ -560,13 +560,13 @@ DataSet f_getPeakExportWeekDataSet() double f_getCurrentChargingInformation() {/*ALCODESTART::1758209089894*/ v_currentChargingPower_kW = 0; -v_currentNumberOfChargingChargePoints = 0; +v_currentNumberOfChargeRequests = 0; for(GridConnection GC : c_connectedGridConnections){ if(GC instanceof GCPublicCharger){ for(J_EAChargePoint charger : GC.c_chargers){ v_currentChargingPower_kW += charger.getLastFlows().get(OL_EnergyCarriers.ELECTRICITY); - v_currentNumberOfChargingChargePoints += charger.getCurrentNumberOfChargingSockets(); + v_currentNumberOfChargeRequests += charger.getCurrentNumberOfChargeRequests(); } } } diff --git a/_alp/Agents/GridNode/Variables.xml b/_alp/Agents/GridNode/Variables.xml index 28b8c6c3..913d5c51 100644 --- a/_alp/Agents/GridNode/Variables.xml +++ b/_alp/Agents/GridNode/Variables.xml @@ -1218,7 +1218,7 @@ geupdate vanuit 1758209124347 - + 810 650 diff --git a/_alp/Agents/GridConnection/Code/Functions.java b/_alp/Agents/GridConnection/Code/Functions.java index eac3ddc0..2bc50dfc 100644 --- a/_alp/Agents/GridConnection/Code/Functions.java +++ b/_alp/Agents/GridConnection/Code/Functions.java @@ -556,11 +556,11 @@ else if (productionAsset.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL){ c_profileAssets.add(profileAsset); } else if (j_ea instanceof J_EADieselTractor tractor) { c_profileAssets.add(tractor); -} else if (j_ea instanceof J_EAChargePoint charger) { +} else if (j_ea instanceof J_EAChargingSession chargingSession) { if(p_chargingManagement == null){ f_addChargingManagement(OL_ChargingAttitude.SIMPLE); } - c_chargers.add(charger); + c_chargingSessions.add(chargingSession); } else { if (!(this instanceof GCHouse && j_ea instanceof J_EAAirco)) { traceln("Unrecognized energy asset %s in gridconnection %s", j_ea, this); diff --git a/_alp/Agents/GridConnection/Code/Functions.xml b/_alp/Agents/GridConnection/Code/Functions.xml index 36ddc0cd..2d5fe2f3 100644 --- a/_alp/Agents/GridConnection/Code/Functions.xml +++ b/_alp/Agents/GridConnection/Code/Functions.xml @@ -795,7 +795,7 @@ 650 - 500 + 520