From 48b04ede2aebddf59bb1ef7c364f7f95b0faf401 Mon Sep 17 00:00:00 2001 From: Luc-Sol Date: Thu, 23 Jan 2025 15:41:01 +0100 Subject: [PATCH 1/2] Added a new J_EADieselTractor also added a collection to the GC canvas for these assets and updateAllFlows at operateFixedAssets --- Zero_engine.alpx | 4 + _alp/Agents/EnergyModel/Code/Functions.java | 2 +- .../Agents/GridConnection/Code/Functions.java | 8 +- _alp/Agents/GridConnection/Variables.xml | 18 +++++ _alp/Classes/Class.J_EADieselTractor.java | 77 +++++++++++++++++++ 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 _alp/Classes/Class.J_EADieselTractor.java diff --git a/Zero_engine.alpx b/Zero_engine.alpx index 0ffa0b8a..6b624322 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1450,6 +1450,10 @@ 1737025326025 + + 1737633433233 + + com.anylogic.libraries.modules.markup_descriptors diff --git a/_alp/Agents/EnergyModel/Code/Functions.java b/_alp/Agents/EnergyModel/Code/Functions.java index f9d2134f..334f088d 100644 --- a/_alp/Agents/EnergyModel/Code/Functions.java +++ b/_alp/Agents/EnergyModel/Code/Functions.java @@ -1061,7 +1061,7 @@ null, roundToDecimal( a.v_electricityImported_kWh-a.v_electricityExported_kWh, 2 int v_timeStepsElapsed_live = v_timeStepsElapsed; v_timeStepsElapsed=0; -c_profiles.forEach(p -> p.updateValue(p_runStartTime_h)); +c_profiles.forEach(p -> p.updateValue(p_runStartTime_h)); c_forecasts.forEach(p -> p.initializeForecast(p_runStartTime_h)); //c_forecasts.parallelStream().forEach(p -> p.initializeForecast(p_runStartTime_h)); diff --git a/_alp/Agents/GridConnection/Code/Functions.java b/_alp/Agents/GridConnection/Code/Functions.java index 46315081..570e88ba 100644 --- a/_alp/Agents/GridConnection/Code/Functions.java +++ b/_alp/Agents/GridConnection/Code/Functions.java @@ -14,8 +14,8 @@ //p_parentNodeHeat = myParentNodeHeat; } -if (p_ownerID!=null){ - ConnectionOwner myParentConnectionOwner = findFirst(energyModel.pop_connectionOwners, p->p.p_actorID.equals(p_ownerID)) ; +if (p_owner!=null){ + ConnectionOwner myParentConnectionOwner = p_owner; //findFirst(energyModel.pop_connectionOwners, p->p.p_actorID.equals(p_ownerID)) ; if( myParentConnectionOwner instanceof ConnectionOwner) { //p_ownerActor = myParentConnectionOwner; l_ownerActor.connectTo(myParentConnectionOwner); @@ -408,7 +408,7 @@ else if (j_ea instanceof J_EAConversionCurtailer || j_ea instanceof J_EAConversi c_consumptionAssets.forEach(c -> c.f_updateAllFlows(0)); c_productionAssets.forEach(p -> p.f_updateAllFlows(0)); c_profileAssets.forEach(p -> p.f_updateAllFlows(energyModel.t_h)); - +c_tractorAssets.forEach(p -> p.f_updateAllFlows(energyModel.t_h)); /*ALCODEEND*/} double f_resetStates() @@ -1242,6 +1242,8 @@ else if (j_ea.energyAssetType == OL_EnergyAssetType.CHP) { } else { traceln( "Unrecognized profile type!"); } +} else if (j_ea instanceof J_EADieselTractor) { + c_tractorAssets.add(j_ea); } else { traceln("Unrecognized energy asset %s in gridconnection %s", j_ea, this); } diff --git a/_alp/Agents/GridConnection/Variables.xml b/_alp/Agents/GridConnection/Variables.xml index 999d76a9..d4e780a7 100644 --- a/_alp/Agents/GridConnection/Variables.xml +++ b/_alp/Agents/GridConnection/Variables.xml @@ -6137,4 +6137,22 @@ String + + 1737642450668 + + 600 + 250 + + false + true + true + + ArrayList + J_EA + String + + diff --git a/_alp/Classes/Class.J_EADieselTractor.java b/_alp/Classes/Class.J_EADieselTractor.java new file mode 100644 index 00000000..eb93a8f2 --- /dev/null +++ b/_alp/Classes/Class.J_EADieselTractor.java @@ -0,0 +1,77 @@ +import java.util.*; + +/** + * J_EADieselTractor + */ +public class J_EADieselTractor extends J_EA implements Serializable { + Double[] dieselConsumptionPerWeek; + Double yearlyDieselConsumption_l; + + /** + * Default constructor + */ + public J_EADieselTractor() { + } + + /** + * Constructor initializing the fields + */ + public J_EADieselTractor(Agent parentAgent, Double yearlyDieselConsumption_l, Double[] dieselConsumptionPerWeek, double timeStep_h) { + this.parentAgent = parentAgent; + this.yearlyDieselConsumption_l = yearlyDieselConsumption_l; + this.dieselConsumptionPerWeek = dieselConsumptionPerWeek; + this.timestep_h = timeStep_h; + + this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.DIESEL); + registerEnergyAsset(); + } + + @Override + public void f_updateAllFlows(double t_h) { + operate(t_h); + if (parentAgent instanceof GridConnection) { + ((GridConnection)parentAgent).f_addFlows(flowsMap, this.energyUse_kW, this); + } + this.lastFlowsMap.cloneMap(this.flowsMap); + this.lastEnergyUse_kW = this.energyUse_kW; + this.clear(); + } + + @Override + public void operate(double t_h) { + double timeOfDay = t_h % 24; + if (timeOfDay < 6 || timeOfDay > 17) { + this.flowsMap.clear(); + return; + } + if (parentAgent instanceof GridConnection) { + if (!((GridConnection)parentAgent).energyModel.b_isWeekday) { + this.flowsMap.clear(); + return; + } + } + // TODO: Extract this calculation from operate and only do this once a week and store dieselPerTimeStep + int week = (int)(t_h / 168); + double weeklyDieselConsumption_l = this.dieselConsumptionPerWeek[week] / Arrays.stream(dieselConsumptionPerWeek).mapToDouble(f -> f.doubleValue()).sum() * this.yearlyDieselConsumption_l; + double weeklyDieselConsumption_kWh = weeklyDieselConsumption_l * 9.7; + int totalWorkTimeSteps = roundToInt(5 * (17 - 6) / this.timestep_h); + double dieselPerTimeStep_kW = weeklyDieselConsumption_l / totalWorkTimeSteps; + + this.flowsMap.put(OL_EnergyCarriers.DIESEL, dieselPerTimeStep_kW); + this.energyUse_kW = dieselPerTimeStep_kW; + this.energyUsed_kWh += this.energyUse_kW * this.timestep_h; + } + + + @Override + public String toString() { + return super.toString(); + } + + /** + * 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 From 99af8b4b1590be2185fdeb8b50c9bf4fca486b25 Mon Sep 17 00:00:00 2001 From: Erik van Velzen Date: Thu, 30 Jan 2025 14:01:43 +0100 Subject: [PATCH 2/2] Refactor diesel tractor I am aware that this is nitpicking and doesn't solve any fundamental issue. --- Zero_engine.alpx | 2 +- .../Agents/GridConnection/Code/Functions.java | 3 +- _alp/Agents/GridConnection/Variables.xml | 20 +- _alp/Classes/Class.J_EADieselTractor.java | 173 +++++++++++------- 4 files changed, 111 insertions(+), 87 deletions(-) diff --git a/Zero_engine.alpx b/Zero_engine.alpx index 6b624322..8559d95b 100644 --- a/Zero_engine.alpx +++ b/Zero_engine.alpx @@ -1,7 +1,7 @@ 1658477103134 diff --git a/_alp/Agents/GridConnection/Code/Functions.java b/_alp/Agents/GridConnection/Code/Functions.java index 570e88ba..e2f39206 100644 --- a/_alp/Agents/GridConnection/Code/Functions.java +++ b/_alp/Agents/GridConnection/Code/Functions.java @@ -408,7 +408,6 @@ else if (j_ea instanceof J_EAConversionCurtailer || j_ea instanceof J_EAConversi c_consumptionAssets.forEach(c -> c.f_updateAllFlows(0)); c_productionAssets.forEach(p -> p.f_updateAllFlows(0)); c_profileAssets.forEach(p -> p.f_updateAllFlows(energyModel.t_h)); -c_tractorAssets.forEach(p -> p.f_updateAllFlows(energyModel.t_h)); /*ALCODEEND*/} double f_resetStates() @@ -1243,7 +1242,7 @@ else if (j_ea.energyAssetType == OL_EnergyAssetType.CHP) { traceln( "Unrecognized profile type!"); } } else if (j_ea instanceof J_EADieselTractor) { - c_tractorAssets.add(j_ea); + c_profileAssets.add(j_ea); } else { traceln("Unrecognized energy asset %s in gridconnection %s", j_ea, this); } diff --git a/_alp/Agents/GridConnection/Variables.xml b/_alp/Agents/GridConnection/Variables.xml index d4e780a7..e157c341 100644 --- a/_alp/Agents/GridConnection/Variables.xml +++ b/_alp/Agents/GridConnection/Variables.xml @@ -5875,7 +5875,7 @@ true ArrayList - J_EAProfile + J_EA String @@ -6137,22 +6137,4 @@ String - - 1737642450668 - - 600 - 250 - - false - true - true - - ArrayList - J_EA - String - - diff --git a/_alp/Classes/Class.J_EADieselTractor.java b/_alp/Classes/Class.J_EADieselTractor.java index eb93a8f2..ce3c44a8 100644 --- a/_alp/Classes/Class.J_EADieselTractor.java +++ b/_alp/Classes/Class.J_EADieselTractor.java @@ -1,77 +1,120 @@ import java.util.*; -/** - * J_EADieselTractor - */ public class J_EADieselTractor extends J_EA implements Serializable { - Double[] dieselConsumptionPerWeek; - Double yearlyDieselConsumption_l; - - /** - * Default constructor - */ - public J_EADieselTractor() { - } + final static double DIESEL_ENERGY_DENSITY_KWH_PER_L = 9.7; + final double[] dieselConsumptionPerWeek_L; + final double workDayStart_h = 6; + final double workDayEnd_h = 17; + /** - * Constructor initializing the fields + * @param parentAgent + * @param yearlyDieselConsumption_l diesel consumption of a single tractor for a whole year + * @param dieselConsumptionPerWeek profile of a year of diesel consumption. + * Usually expressed in L per ha per week for a specific crop or mix of crops. + * For our purpose the unit doesn't matter. + * @param timeStep_h */ - public J_EADieselTractor(Agent parentAgent, Double yearlyDieselConsumption_l, Double[] dieselConsumptionPerWeek, double timeStep_h) { - this.parentAgent = parentAgent; - this.yearlyDieselConsumption_l = yearlyDieselConsumption_l; - this.dieselConsumptionPerWeek = dieselConsumptionPerWeek; - this.timestep_h = timeStep_h; - - this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.DIESEL); - registerEnergyAsset(); + public J_EADieselTractor(Agent parentAgent, double yearlyDieselConsumption_L, double[] dieselConsumptionPerWeek, double timeStep_h) { + if (parentAgent == null) { + throw new RuntimeException("Diesel tractor missing parent agent"); + } + + if (yearlyDieselConsumption_L <= 100.0) { + throw new RuntimeException( + String.format("Diesel tractor fuel usage conspicuously low: %d L", yearlyDieselConsumption_L) + ); + } + + if (dieselConsumptionPerWeek == null) { + throw new RuntimeException("Tractor diesel consumption profile is null"); + } + + if (dieselConsumptionPerWeek.length != 52) { + throw new RuntimeException( + String.format("Tractor diesel consumption profile has %d weeks instead of 52", dieselConsumptionPerWeek.length) + ); + } + + if (timeStep_h <= 0.0) { + throw new RuntimeException("Tractor timestep is off"); + } + + this.parentAgent = parentAgent; + this.dieselConsumptionPerWeek_L = calculateDieselConsumptionPerWeek_L(yearlyDieselConsumption_L, dieselConsumptionPerWeek); + this.timestep_h = timeStep_h; + + this.activeConsumptionEnergyCarriers.add(OL_EnergyCarriers.DIESEL); + registerEnergyAsset(); } @Override public void f_updateAllFlows(double t_h) { - operate(t_h); - if (parentAgent instanceof GridConnection) { - ((GridConnection)parentAgent).f_addFlows(flowsMap, this.energyUse_kW, this); - } - this.lastFlowsMap.cloneMap(this.flowsMap); - this.lastEnergyUse_kW = this.energyUse_kW; - this.clear(); + operate(t_h); + if (parentAgent instanceof GridConnection) { + ((GridConnection)parentAgent).f_addFlows(flowsMap, this.energyUse_kW, this); + } + this.lastFlowsMap.cloneMap(this.flowsMap); + this.lastEnergyUse_kW = this.energyUse_kW; + this.clear(); } - @Override - public void operate(double t_h) { - double timeOfDay = t_h % 24; - if (timeOfDay < 6 || timeOfDay > 17) { - this.flowsMap.clear(); - return; - } - if (parentAgent instanceof GridConnection) { - if (!((GridConnection)parentAgent).energyModel.b_isWeekday) { - this.flowsMap.clear(); - return; - } - } - // TODO: Extract this calculation from operate and only do this once a week and store dieselPerTimeStep - int week = (int)(t_h / 168); - double weeklyDieselConsumption_l = this.dieselConsumptionPerWeek[week] / Arrays.stream(dieselConsumptionPerWeek).mapToDouble(f -> f.doubleValue()).sum() * this.yearlyDieselConsumption_l; - double weeklyDieselConsumption_kWh = weeklyDieselConsumption_l * 9.7; - int totalWorkTimeSteps = roundToInt(5 * (17 - 6) / this.timestep_h); - double dieselPerTimeStep_kW = weeklyDieselConsumption_l / totalWorkTimeSteps; - - this.flowsMap.put(OL_EnergyCarriers.DIESEL, dieselPerTimeStep_kW); - this.energyUse_kW = dieselPerTimeStep_kW; - this.energyUsed_kWh += this.energyUse_kW * this.timestep_h; - } - - - @Override - public String toString() { - return super.toString(); - } - - /** - * 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 + @Override + public void operate(double t_h) { + if (!shouldWork(t_h)) { + this.flowsMap.clear(); + return; + } + + double currentPower_kW = currentPower_kW(t_h); + + this.flowsMap.put(OL_EnergyCarriers.DIESEL, currentPower_kW); + this.energyUse_kW = currentPower_kW; + this.energyUsed_kWh += currentPower_kW * timestep_h; + } + + private static double[] calculateDieselConsumptionPerWeek_L(double yearlyDieselConsumption_l, double[] weekProfile) { + var profileSum = Arrays.stream(weekProfile).sum(); + + return Arrays.stream(weekProfile) + .map(weekValue -> yearlyDieselConsumption_l * weekValue / profileSum) + .toArray(); + } + + private boolean shouldWork(double currentStep_h) { + return isWorkTime(currentStep_h) && isWorkDay(); + } + + private boolean isWorkTime(double currentStep_h) { + double timeOfDay = currentStep_h % 24; + + return timeOfDay >= workDayStart_h && timeOfDay < workDayEnd_h; + } + + private boolean isWorkDay() { + return ((GridConnection)parentAgent).energyModel.b_isWeekday; + } + + private double workHoursPerWeek() { + return 5 * (workDayEnd_h - workDayStart_h); + } + + private int workTimeStepsPerWeek() { + return roundToInt(workHoursPerWeek() / this.timestep_h); + } + + private double currentPower_kW(double currentStep_h) { + int week = (int) Math.round(currentStep_h / (7 * 24)); + + double thisWeekDieselConsumption_L = this.dieselConsumptionPerWeek_L[week]; + double thisWeekDieselConsumption_kWh = thisWeekDieselConsumption_L * DIESEL_ENERGY_DENSITY_KWH_PER_L; + double power_kW = thisWeekDieselConsumption_kWh / workHoursPerWeek(); + return power_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; +}