diff --git a/Zero_engine.alpx b/Zero_engine.alpx index e6cc477e..4a5e381e 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1781,6 +1781,16 @@ 1762850578079 + + 1763557451043 + + 1762850578079 + + + 1763570262548 + + 1752680962144 + com.anylogic.libraries.modules.markup_descriptors diff --git a/_alp/Classes/Class.J_EAConversion.java b/_alp/Classes/Class.J_EAConversion.java index cfbbcde7..15fc141f 100644 --- a/_alp/Classes/Class.J_EAConversion.java +++ b/_alp/Classes/Class.J_EAConversion.java @@ -33,7 +33,8 @@ public J_EAConversion(Agent parentAgent, OL_EnergyAssetType energyAssetType, dou @Override public void f_updateAllFlows(double powerFraction_fr) { - if ( powerFraction_fr < 0 ) { + powerFraction_fr = roundToDecimal(powerFraction_fr, J_GlobalParameters.floatingPointPrecision); + if(powerFraction_fr < 0) { throw new RuntimeException("Impossible to operate conversion asset with negative powerfraction."); } else if ( powerFraction_fr == 0 ) { diff --git a/_alp/Classes/Class.J_GlobalParameters.java b/_alp/Classes/Class.J_GlobalParameters.java new file mode 100644 index 00000000..199e2ec5 --- /dev/null +++ b/_alp/Classes/Class.J_GlobalParameters.java @@ -0,0 +1,7 @@ +/** + * J_GlobalParameters + */ +public abstract class J_GlobalParameters { + //public final static double floatingPointErrorMargin = 1e-15; + public final static int floatingPointPrecision = 15; +} \ No newline at end of file diff --git a/_alp/Classes/Class.J_HeatingFunctionLibrary.java b/_alp/Classes/Class.J_HeatingFunctionLibrary.java new file mode 100644 index 00000000..a61b29be --- /dev/null +++ b/_alp/Classes/Class.J_HeatingFunctionLibrary.java @@ -0,0 +1,76 @@ +/** + * J_HeatingFunctionLibrary + */ +public abstract class J_HeatingFunctionLibrary { + + public static double managePTAndHotWaterHeatBuffer(J_EAStorageHeat hotWaterBuffer, List ptAssets, double hotWaterDemand_kW){ + //Calculate the pt production + double ptProduction_kW = 0; + for (J_EA j_ea : ptAssets) { + ptProduction_kW -= j_ea.getLastFlows().get(OL_EnergyCarriers.HEAT); + } + + //Calculate the remaining hot water energy need after pt production, also calculate the remaining unused pt production + double remainingHotWater_kW = max(0, hotWaterDemand_kW - ptProduction_kW); // Need to do this, because pt has already compensated the hot water demand in the gc flows, so just need to update this value + double remainingPTProduction_kW = max(0, ptProduction_kW - hotWaterDemand_kW); + + if(hotWaterBuffer != null){ + double chargeSetpoint_kW = 0; + if(remainingHotWater_kW > 0) { + chargeSetpoint_kW = -remainingHotWater_kW; + } + else if(remainingPTProduction_kW > 0) { + chargeSetpoint_kW = remainingPTProduction_kW; + } + hotWaterBuffer.v_powerFraction_fr = chargeSetpoint_kW / hotWaterBuffer.getCapacityHeat_kW(); + hotWaterBuffer.f_updateAllFlows(hotWaterBuffer.v_powerFraction_fr); + + double heatBufferCharge_kW = hotWaterBuffer.getLastFlows().get(OL_EnergyCarriers.HEAT); + + if(remainingHotWater_kW > 0){//Only if the current pt production, wasnt enough, adjust the hotwater demand with the buffer, cause then the buffer will have tried to discharge + remainingHotWater_kW = max(0, remainingHotWater_kW + heatBufferCharge_kW); + } + else {//Curtail the remaining pt that is not used for hot water + remainingPTProduction_kW = max(0, remainingPTProduction_kW - heatBufferCharge_kW); + } + } + + if (remainingPTProduction_kW > 0) {//Heat (for now always curtail over produced heat!) + for (J_EAProduction j_ea : ptAssets) { + remainingPTProduction_kW -= j_ea.curtailEnergyCarrierProduction( OL_EnergyCarriers.HEAT, remainingPTProduction_kW); + + if (remainingPTProduction_kW <= 0) { + break; + } + } + } + return remainingHotWater_kW; + } + + public static double manageHotWaterHeatBuffer(J_EAStorageHeat hotWaterBuffer, double hotWaterDemand_kW, double availableHeatingPower_kWth, double timeStep_h){ + if(hotWaterDemand_kW > availableHeatingPower_kWth + hotWaterBuffer.getCurrentStateOfCharge_kWh() / timeStep_h) { + throw new RuntimeException("Hot water demand is higher than available power."); + } + + //Heating asset should always try to fill the heat buffer as fast as possible. + double hotWaterDemandFromHeatingAsset_kW = min(availableHeatingPower_kWth, hotWaterDemand_kW + (hotWaterBuffer.getStorageCapacity_kWh() - hotWaterBuffer.getCurrentStateOfCharge_kWh())); + double heatIntoBuffer_kW = hotWaterDemandFromHeatingAsset_kW - hotWaterDemand_kW; + + + hotWaterBuffer.v_powerFraction_fr = heatIntoBuffer_kW / hotWaterBuffer.getCapacityHeat_kW(); + hotWaterBuffer.f_updateAllFlows(hotWaterBuffer.v_powerFraction_fr); + + + return hotWaterDemandFromHeatingAsset_kW; + } +} + + + + + + + + + + \ No newline at end of file diff --git a/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java b/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java index 9cdb899f..516165e0 100644 --- a/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java +++ b/_alp/Classes/Class.J_HeatingManagementHeatpumpOffPeak.java @@ -24,7 +24,11 @@ public class J_HeatingManagementHeatpumpOffPeak implements I_HeatingManagement { private J_EABuilding building; private J_EAConversion heatingAsset; private J_HeatingPreferences heatingPreferences; - + private J_EAStorageHeat hotWaterBuffer; + private List ptAssets; + private boolean hasPT = false; + private boolean hasHotWaterBuffer = false; + // PI control gains private double P_gain_kWpDegC = 1*1; private double I_gain_kWphDegC = 0.1*2; @@ -74,13 +78,27 @@ public void manageHeating() { calculatePreHeatParameters(); } - //Adjust the hot water and overall heat demand with the buffer and pt double hotWaterDemand_kW = gc.p_DHWAsset != null ? gc.p_DHWAsset.getLastFlows().get(OL_EnergyCarriers.HEAT) : 0; - double remainingHotWaterDemand_kW = managePTAndHotWaterHeatBuffer(hotWaterDemand_kW); + double ptAssetPower_kW = ptAssets != null ? sum(ptAssets, pt -> pt.getLastFlows().get(OL_EnergyCarriers.HEAT)) : 0; + double additionalHeatDemand_kW = (gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT) - hotWaterDemand_kW + (-ptAssetPower_kW)); + + double currentHeatDemand_kW = additionalHeatDemand_kW; + double availableAssetPowerForHotWater_kWth = heatingAsset.getOutputCapacity_kW() - additionalHeatDemand_kW; + + //Manage hot water if additional systems are present + if(this.hasPT) { + //Adjust the hot water and overall heat demand with the buffer and pt + double remainingHotWaterDemand_kW = J_HeatingFunctionLibrary.managePTAndHotWaterHeatBuffer(hotWaterBuffer, ptAssets, hotWaterDemand_kW); // This function updates the buffer and curtails PT if needed -> current balanceflow is updated accordingly. + currentHeatDemand_kW += remainingHotWaterDemand_kW; + } + else if(this.hasHotWaterBuffer) { + double heatDemandFromHeatingAssetForHotWater_kW = J_HeatingFunctionLibrary.manageHotWaterHeatBuffer(this.hotWaterBuffer, hotWaterDemand_kW, availableAssetPowerForHotWater_kWth, this.timeStep_h); + currentHeatDemand_kW += heatDemandFromHeatingAssetForHotWater_kW; + } + else { + currentHeatDemand_kW += hotWaterDemand_kW; + } - //Get the remaining heat demand (hot water, and potential other profiles) - double otherHeatDemand_kW = gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT); - //Determine if time is in reduced Heating interval boolean timeIsInReducedHeatingInterval = ((timeOfDay_h - startTimeOfReducedHeatingInterval_hr + 24) % 24) < reducedHeatingIntervalLength_hr; boolean timeIsInPreheatInterval = ((timeOfDay_h - (startTimeOfReducedHeatingInterval_hr - preHeatDuration_hr) + 24) % 24) < preHeatDuration_hr; @@ -115,11 +133,11 @@ else if (timeOfDay_h < heatingPreferences.getStartOfDayTime_h() || timeOfDay_h > double buildingHeatingDemand_kW = max(0,deltaT_degC * P_gain_kWpDegC + I_state_hDegC * I_gain_kWphDegC); //Set asset power - double assetPower_kW = min(heatingAsset.getOutputCapacity_kW(), buildingHeatingDemand_kW + otherHeatDemand_kW); // minimum not strictly needed as asset will limit power by itself. Could be used later if we notice demand is higher than capacity of heating asset. + double assetPower_kW = min(heatingAsset.getOutputCapacity_kW(), buildingHeatingDemand_kW + currentHeatDemand_kW); // minimum not strictly needed as asset will limit power by itself. Could be used later if we notice demand is higher than capacity of heating asset. heatingAsset.f_updateAllFlows( assetPower_kW / heatingAsset.getOutputCapacity_kW() ); //Set building power (other heat demand gets bias if asset does not have enough capacity) - double heatIntoBuilding_kW = max(0, assetPower_kW - otherHeatDemand_kW); + double heatIntoBuilding_kW = max(0, assetPower_kW - currentHeatDemand_kW); building.f_updateAllFlows( heatIntoBuilding_kW / building.getCapacityHeat_kW() ); } @@ -188,53 +206,6 @@ private void calculatePreHeatParameters() { //For now, preheat duration of 2 hours is assumed. } } - - private double managePTAndHotWaterHeatBuffer(double hotWaterDemand_kW){ - - //Calculate the pt production - double ptProduction_kW = 0; - List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - for (J_EA j_ea : ptAssets) { - ptProduction_kW -= j_ea.getLastFlows().get(OL_EnergyCarriers.HEAT); - } - - //Calculate the remaining hot water energy need after pt production, also calculate the remaining unused pt production - double remainingHotWater_kW = max(0, hotWaterDemand_kW - ptProduction_kW); // Need to do this, because pt has already compensated the hot water demand in the gc flows, so just need to update this value - double remainingPTProduction_kW = max(0, ptProduction_kW - hotWaterDemand_kW); - - if(gc.p_heatBuffer != null){ - double chargeSetpoint_kW = 0; - if(remainingHotWater_kW > 0) { - chargeSetpoint_kW = -remainingHotWater_kW; - } - else if(remainingPTProduction_kW > 0) { - chargeSetpoint_kW = remainingPTProduction_kW; - } - gc.p_heatBuffer.v_powerFraction_fr = chargeSetpoint_kW / gc.p_heatBuffer.getCapacityHeat_kW(); - gc.p_heatBuffer.f_updateAllFlows(gc.p_heatBuffer.v_powerFraction_fr); - - double heatBufferCharge_kW = gc.p_heatBuffer.getLastFlows().get(OL_EnergyCarriers.HEAT); - - if(remainingHotWater_kW > 0){//Only if the current pt production, wasnt enough, adjust the hotwater demand with the buffer, cause then the buffer will have tried to discharge - remainingHotWater_kW = max(0, remainingHotWater_kW + heatBufferCharge_kW); - } - else {//Curtail the remaining pt that is not used for hot water - remainingPTProduction_kW = max(0, remainingPTProduction_kW - heatBufferCharge_kW); - if (remainingPTProduction_kW > 0) {//Heat (for now always curtail over produced heat!) - for (J_EAProduction j_ea : ptAssets) { - remainingPTProduction_kW -= j_ea.curtailEnergyCarrierProduction( OL_EnergyCarriers.HEAT, remainingPTProduction_kW); - - if (remainingPTProduction_kW <= 0) { - break; - } - } - } - } - } - return remainingHotWater_kW; - } - - public void setStartTimeOfReducedHeatingInterval_hr(double startTimeOfReducedHeatingInterval_hr) { @@ -268,16 +239,20 @@ public void initializeAssets() { if (!validHeatingTypes.contains(this.currentHeatingType)) { throw new RuntimeException(this.getClass() + " does not support heating type: " + this.currentHeatingType); } - J_EAProduction ptAsset = findFirst(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - if (ptAsset != null) { + List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); + if (ptAssets.size() > 0) { if(gc.p_DHWAsset == null) { throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with PT."); } + this.ptAssets = ptAssets; + this.hasPT = true; } if (gc.p_heatBuffer != null) { - if(gc.p_DHWAsset == null && ptAsset == null) { - throw new RuntimeException(this.getClass() + " requires a hot water demand and PT to make sense to use this heating management with a heatbuffer."); + if(gc.p_DHWAsset == null) { + throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with a heatbuffer."); } + this.hotWaterBuffer = gc.p_heatBuffer; + this.hasHotWaterBuffer = true; } if(gc.p_BuildingThermalAsset != null) { this.building = gc.p_BuildingThermalAsset; diff --git a/_alp/Classes/Class.J_HeatingManagementPIcontrol.java b/_alp/Classes/Class.J_HeatingManagementPIcontrol.java index 109d83bf..8c6966c6 100644 --- a/_alp/Classes/Class.J_HeatingManagementPIcontrol.java +++ b/_alp/Classes/Class.J_HeatingManagementPIcontrol.java @@ -29,7 +29,11 @@ public class J_HeatingManagementPIcontrol implements I_HeatingManagement { private J_EABuilding building; private J_EAConversion heatingAsset; private J_HeatingPreferences heatingPreferences; - + private J_EAStorageHeat hotWaterBuffer; + private List ptAssets; + private boolean hasPT = false; + private boolean hasHotWaterBuffer = false; + // PI control gains private double P_gain_kWpDegC = 1*1; private double I_gain_kWphDegC = 0.1*2; @@ -61,11 +65,26 @@ public void manageHeating() { } double hotWaterDemand_kW = gc.p_DHWAsset != null ? gc.p_DHWAsset.getLastFlows().get(OL_EnergyCarriers.HEAT) : 0; + double ptAssetPower_kW = ptAssets != null ? sum(ptAssets, pt -> pt.getLastFlows().get(OL_EnergyCarriers.HEAT)) : 0; + double additionalHeatDemand_kW = (gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT) - hotWaterDemand_kW + (-ptAssetPower_kW)); + + double currentHeatDemand_kW = additionalHeatDemand_kW; + double availableAssetPowerForHotWater_kWth = heatingAsset.getOutputCapacity_kW() - additionalHeatDemand_kW; - //Adjust the hot water and overall heat demand with the buffer and pt - double remainingHotWaterDemand_kW = managePTAndHotWaterHeatBuffer(hotWaterDemand_kW); + //Manage hot water if additional systems are present + if(this.hasPT) { + //Adjust the hot water and overall heat demand with the buffer and pt + double remainingHotWaterDemand_kW = J_HeatingFunctionLibrary.managePTAndHotWaterHeatBuffer(hotWaterBuffer, ptAssets, hotWaterDemand_kW); // This function updates the buffer and curtails PT if needed -> current balanceflow is updated accordingly. + currentHeatDemand_kW += remainingHotWaterDemand_kW; + } + else if(this.hasHotWaterBuffer) { + double heatDemandFromHeatingAssetForHotWater_kW = J_HeatingFunctionLibrary.manageHotWaterHeatBuffer(this.hotWaterBuffer, hotWaterDemand_kW, availableAssetPowerForHotWater_kWth, this.timeStep_h); + currentHeatDemand_kW += heatDemandFromHeatingAssetForHotWater_kW; + } + else { + currentHeatDemand_kW += hotWaterDemand_kW; + } - double otherHeatDemand_kW = gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT); double buildingTemp_degC = building.getCurrentTemperature(); double timeOfDay_h = gc.energyModel.t_hourOfDay; @@ -86,73 +105,33 @@ public void manageHeating() { buildingHeatingDemand_kW = max(0,deltaT_degC * P_gain_kWpDegC + I_state_hDegC * I_gain_kWphDegC); - double assetPower_kW = min(heatingAsset.getOutputCapacity_kW(),buildingHeatingDemand_kW + otherHeatDemand_kW); // minimum not strictly needed as asset will limit power by itself. Could be used later if we notice demand is higher than capacity of heating asset. + double assetPower_kW = min(heatingAsset.getOutputCapacity_kW(),buildingHeatingDemand_kW + currentHeatDemand_kW); // minimum not strictly needed as asset will limit power by itself. Could be used later if we notice demand is higher than capacity of heating asset. heatingAsset.f_updateAllFlows( assetPower_kW / heatingAsset.getOutputCapacity_kW() ); - double heatIntoBuilding_kW = max(0, assetPower_kW - otherHeatDemand_kW); + double heatIntoBuilding_kW = max(0, assetPower_kW - currentHeatDemand_kW); building.f_updateAllFlows( heatIntoBuilding_kW / building.getCapacityHeat_kW() ); } - private double managePTAndHotWaterHeatBuffer(double hotWaterDemand_kW){ - - //Calculate the pt production - double ptProduction_kW = 0; - List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - for (J_EA j_ea : ptAssets) { - ptProduction_kW -= j_ea.getLastFlows().get(OL_EnergyCarriers.HEAT); - } - - //Calculate the remaining hot water energy need after pt production, also calculate the remaining unused pt production - double remainingHotWater_kW = max(0, hotWaterDemand_kW - ptProduction_kW); // Need to do this, because pt has already compensated the hot water demand in the gc flows, so just need to update this value - double remainingPTProduction_kW = max(0, ptProduction_kW - hotWaterDemand_kW); - - if(gc.p_heatBuffer != null){ - double chargeSetpoint_kW = 0; - if(remainingHotWater_kW > 0) { - chargeSetpoint_kW = -remainingHotWater_kW; - } - else if(remainingPTProduction_kW > 0) { - chargeSetpoint_kW = remainingPTProduction_kW; - } - gc.p_heatBuffer.v_powerFraction_fr = chargeSetpoint_kW / gc.p_heatBuffer.getCapacityHeat_kW(); - gc.p_heatBuffer.f_updateAllFlows(gc.p_heatBuffer.v_powerFraction_fr); - - double heatBufferCharge_kW = gc.p_heatBuffer.getLastFlows().get(OL_EnergyCarriers.HEAT); - - if(remainingHotWater_kW > 0){//Only if the current pt production, wasnt enough, adjust the hotwater demand with the buffer, cause then the buffer will have tried to discharge - remainingHotWater_kW = max(0, remainingHotWater_kW + heatBufferCharge_kW); - } - else {//Curtail the remaining pt that is not used for hot water - remainingPTProduction_kW = max(0, remainingPTProduction_kW - heatBufferCharge_kW); - if (remainingPTProduction_kW > 0) {//Heat (for now always curtail over produced heat!) - for (J_EAProduction j_ea : ptAssets) { - remainingPTProduction_kW -= j_ea.curtailEnergyCarrierProduction( OL_EnergyCarriers.HEAT, remainingPTProduction_kW); - - if (remainingPTProduction_kW <= 0) { - break; - } - } - } - } - } - return remainingHotWater_kW; - } public void initializeAssets() { if (!validHeatingTypes.contains(this.currentHeatingType)) { throw new RuntimeException(this.getClass() + " does not support heating type: " + this.currentHeatingType); } - J_EAProduction ptAsset = findFirst(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - if (ptAsset != null) { + List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); + if (ptAssets.size() > 0) { if(gc.p_DHWAsset == null) { throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with PT."); } + this.ptAssets = ptAssets; + this.hasPT = true; } if (gc.p_heatBuffer != null) { - if(gc.p_DHWAsset == null && ptAsset == null) { - throw new RuntimeException(this.getClass() + " requires a hot water demand and PT to make sense to use this heating management with a heatbuffer."); + if(gc.p_DHWAsset == null) { + throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with heatbuffer."); } + this.hotWaterBuffer = gc.p_heatBuffer; + this.hasHotWaterBuffer = true; } if(gc.p_BuildingThermalAsset != null) { this.building = gc.p_BuildingThermalAsset; diff --git a/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java b/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java index 11ea6f04..01ddce00 100644 --- a/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java +++ b/_alp/Classes/Class.J_HeatingManagementPIcontrolHybridHeatpump.java @@ -24,6 +24,9 @@ public class J_HeatingManagementPIcontrolHybridHeatpump implements I_HeatingMana private J_EAConversionHeatPump heatPumpAsset; private J_EAConversionGasBurner gasBurnerAsset; private J_HeatingPreferences heatingPreferences; + private J_EAStorageHeat hotWaterBuffer; + private List ptAssets; + private boolean hasPT = false; // PI control gains private double P_gain_kWpDegC = 1*1; @@ -58,8 +61,10 @@ public void manageHeating() { double hotWaterDemand_kW = gc.p_DHWAsset != null ? gc.p_DHWAsset.getLastFlows().get(OL_EnergyCarriers.HEAT) : 0; - //Adjust the hot water and overall heat demand with the buffer and pt - double remainingHotWaterDemand_kW = managePTAndHotWaterHeatBuffer(hotWaterDemand_kW); // This function updates the buffer and curtails PT if needed -> current balanceflow is updated accordingly. + if(hasPT) { + //Adjust the hot water and overall heat demand with the buffer and pt + double remainingHotWaterDemand_kW = J_HeatingFunctionLibrary.managePTAndHotWaterHeatBuffer(hotWaterBuffer, ptAssets, hotWaterDemand_kW); // This function updates the buffer and curtails PT if needed -> current balanceflow is updated accordingly. + } double otherHeatDemand_kW = gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT); @@ -106,66 +111,23 @@ public void manageHeating() { } - private double managePTAndHotWaterHeatBuffer(double hotWaterDemand_kW){ - - //Calculate the pt production - double ptProduction_kW = 0; - List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - for (J_EA j_ea : ptAssets) { - ptProduction_kW -= j_ea.getLastFlows().get(OL_EnergyCarriers.HEAT); - } - - //Calculate the remaining hot water energy need after pt production, also calculate the remaining unused pt production - double remainingHotWater_kW = max(0, hotWaterDemand_kW - ptProduction_kW); // Need to do this, because pt has already compensated the hot water demand in the gc flows, so just need to update this value - double remainingPTProduction_kW = max(0, ptProduction_kW - hotWaterDemand_kW); - - if(gc.p_heatBuffer != null){ - double chargeSetpoint_kW = 0; - if(remainingHotWater_kW > 0) { - chargeSetpoint_kW = -remainingHotWater_kW; - } - else if(remainingPTProduction_kW > 0) { - chargeSetpoint_kW = remainingPTProduction_kW; - } - gc.p_heatBuffer.v_powerFraction_fr = chargeSetpoint_kW / gc.p_heatBuffer.getCapacityHeat_kW(); - gc.p_heatBuffer.f_updateAllFlows(gc.p_heatBuffer.v_powerFraction_fr); - - double heatBufferCharge_kW = gc.p_heatBuffer.getLastFlows().get(OL_EnergyCarriers.HEAT); - - if(remainingHotWater_kW > 0){//Only if the current pt production, wasnt enough, adjust the hotwater demand with the buffer, cause then the buffer will have tried to discharge - remainingHotWater_kW = max(0, remainingHotWater_kW + heatBufferCharge_kW); - } - else {//Curtail the remaining pt that is not used for hot water - remainingPTProduction_kW = max(0, remainingPTProduction_kW - heatBufferCharge_kW); - if (remainingPTProduction_kW > 0) {//Heat (for now always curtail over produced heat!) - for (J_EAProduction j_ea : ptAssets) { - remainingPTProduction_kW -= j_ea.curtailEnergyCarrierProduction( OL_EnergyCarriers.HEAT, remainingPTProduction_kW); - - if (remainingPTProduction_kW <= 0) { - break; - } - } - } - } - } - return remainingHotWater_kW; - } - - public void initializeAssets() { if (!validHeatingTypes.contains(this.currentHeatingType)) { throw new RuntimeException(this.getClass() + " does not support heating type: " + this.currentHeatingType); } - J_EAProduction ptAsset = findFirst(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - if (ptAsset != null) { + List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); + if (ptAssets.size() > 0) { if(gc.p_DHWAsset == null) { throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with PT."); } + this.hasPT = true; + this.ptAssets = ptAssets; } if (gc.p_heatBuffer != null) { - if(gc.p_DHWAsset == null && ptAsset == null) { - throw new RuntimeException(this.getClass() + " requires a hot water demand and PT to make sense to use this heating management with a heatbuffer."); + if(gc.p_DHWAsset == null || ptAssets.size() == 0) { + throw new RuntimeException(this.getClass() + " requires a hot water demand and pt to make sense to use this heating management."); } + this.hotWaterBuffer = gc.p_heatBuffer; } if(gc.p_BuildingThermalAsset != null) { this.building = gc.p_BuildingThermalAsset; diff --git a/_alp/Classes/Class.J_HeatingManagementSimple.java b/_alp/Classes/Class.J_HeatingManagementSimple.java index bad5a140..16c6591e 100644 --- a/_alp/Classes/Class.J_HeatingManagementSimple.java +++ b/_alp/Classes/Class.J_HeatingManagementSimple.java @@ -28,6 +28,9 @@ public class J_HeatingManagementSimple implements I_HeatingManagement { private J_EABuilding building; private J_EAConversion heatingAsset; private J_HeatingPreferences heatingPreferences; + private J_EAStorageHeat hotWaterBuffer; + private List ptAssets; + private boolean hasPT = false; /** * Default constructor @@ -40,52 +43,7 @@ public J_HeatingManagementSimple( GridConnection gc, OL_GridConnectionHeatingTyp this.gc = gc; this.currentHeatingType = heatingType; } - - public double managePTAndHotWaterHeatBuffer(double hotWaterDemand_kW){ - - //Calculate the pt production - double ptProduction_kW = 0; - List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - for (J_EA j_ea : ptAssets) { - ptProduction_kW -= j_ea.getLastFlows().get(OL_EnergyCarriers.HEAT); - } - - //Calculate the remaining hot water energy need after pt production, also calculate the remaining unused pt production - double remainingHotWater_kW = max(0, hotWaterDemand_kW - ptProduction_kW); // Need to do this, because pt has already compensated the hot water demand in the gc flows, so just need to update this value - double remainingPTProduction_kW = max(0, ptProduction_kW - hotWaterDemand_kW); - - if(gc.p_heatBuffer != null){ - double chargeSetpoint_kW = 0; - if(remainingHotWater_kW > 0) { - chargeSetpoint_kW = -remainingHotWater_kW; - } - else if(remainingPTProduction_kW > 0) { - chargeSetpoint_kW = remainingPTProduction_kW; - } - gc.p_heatBuffer.v_powerFraction_fr = chargeSetpoint_kW / gc.p_heatBuffer.getCapacityHeat_kW(); - gc.p_heatBuffer.f_updateAllFlows(gc.p_heatBuffer.v_powerFraction_fr); - - double heatBufferCharge_kW = gc.p_heatBuffer.getLastFlows().get(OL_EnergyCarriers.HEAT); - - if(remainingHotWater_kW > 0){//Only if the current pt production, wasnt enough, adjust the hotwater demand with the buffer, cause then the buffer will have tried to discharge - remainingHotWater_kW = max(0, remainingHotWater_kW + heatBufferCharge_kW); - } - else {//Curtail the remaining pt that is not used for hot water - remainingPTProduction_kW = max(0, remainingPTProduction_kW - heatBufferCharge_kW); - if (remainingPTProduction_kW > 0) {//Heat (for now always curtail over produced heat!) - for (J_EAProduction j_ea : ptAssets) { - remainingPTProduction_kW -= j_ea.curtailEnergyCarrierProduction( OL_EnergyCarriers.HEAT, remainingPTProduction_kW); - - if (remainingPTProduction_kW <= 0) { - break; - } - } - } - } - } - return remainingHotWater_kW; - } - + public void manageHeating() { if ( !isInitialized ) { @@ -94,8 +52,9 @@ public void manageHeating() { double hotWaterDemand_kW = gc.p_DHWAsset != null ? gc.p_DHWAsset.getLastFlows().get(OL_EnergyCarriers.HEAT) : 0; - //Adjust the hot water and overall heat demand with the buffer and pt - double remainingHotWaterDemand_kW = managePTAndHotWaterHeatBuffer(hotWaterDemand_kW); // also updates fm_currentBalanceFlows_kW(heat)! + if(hasPT) {//Adjust the hot water and overall heat demand with the buffer and pt + double remainingHotWaterDemand_kW = J_HeatingFunctionLibrary.managePTAndHotWaterHeatBuffer(hotWaterBuffer, ptAssets, hotWaterDemand_kW); // also updates fm_currentBalanceFlows_kW(heat)! + } double heatDemand_kW = gc.fm_currentBalanceFlows_kW.get(OL_EnergyCarriers.HEAT); @@ -138,16 +97,19 @@ public void initializeAssets() { if (!validHeatingTypes.contains(this.currentHeatingType)) { throw new RuntimeException(this.getClass() + " does not support heating type: " + this.currentHeatingType); } - J_EAProduction ptAsset = findFirst(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); - if (ptAsset != null) { + List ptAssets = findAll(gc.c_productionAssets, ea -> ea.energyAssetType == OL_EnergyAssetType.PHOTOTHERMAL); + if (ptAssets.size() > 0) { if(gc.p_DHWAsset == null) { throw new RuntimeException(this.getClass() + " requires a hot water demand to make sense to use this heating management with PT."); } + this.ptAssets = ptAssets; + this.hasPT = true; } if (gc.p_heatBuffer != null) { - if(gc.p_DHWAsset == null && ptAsset == null) { - throw new RuntimeException(this.getClass() + " requires a hot water demand and PT to make sense to use this heating management with a heatbuffer."); + if(gc.p_DHWAsset == null || ptAssets.size() == 0) { + throw new RuntimeException(this.getClass() + " requires a hot water demand and PT to make sense to use this heating management with heatbuffer."); } + this.hotWaterBuffer = gc.p_heatBuffer; } if(gc.p_BuildingThermalAsset != null) { this.building = gc.p_BuildingThermalAsset;