fix: single objective optimization algorithm is completed. The cooling system needs to be separated in the archetype
This commit is contained in:
parent
59815f4bbf
commit
2ed9555fc8
|
@ -58,7 +58,7 @@ class ArchetypeCluster1:
|
|||
hp = self.building.energy_systems[1].generation_systems[1]
|
||||
cooling_demand_joules = self.building.cooling_demand[cte.HOUR]
|
||||
cooling_peak_load = self.building.cooling_peak_load[cte.YEAR][0]
|
||||
cutoff_temperature = 13
|
||||
cutoff_temperature = 11
|
||||
outdoor_temperature = self.building.external_temperature[cte.HOUR]
|
||||
results = HeatPumpCooling(hp=hp,
|
||||
hourly_cooling_demand_joules=cooling_demand_joules,
|
||||
|
|
|
@ -34,7 +34,7 @@ class EnergySystemsSizingFactory:
|
|||
"""
|
||||
Size Energy Systems using a Single or Multi Objective GA
|
||||
"""
|
||||
HeuristicSizing(self._city).genetic_algorithm()
|
||||
HeuristicSizing(self._city).enrich_buildings()
|
||||
self._city.level_of_detail.energy_systems = 1
|
||||
for building in self._city.buildings:
|
||||
building.level_of_detail.energy_systems = 1
|
||||
|
|
|
@ -38,7 +38,7 @@ class HeatPump:
|
|||
cop_curve_coefficients[2] * t_inlet_water_fahrenheit ** 2 +
|
||||
cop_curve_coefficients[3] * t_source_fahrenheit +
|
||||
cop_curve_coefficients[4] * t_source_fahrenheit ** 2 +
|
||||
cop_curve_coefficients[5] * t_inlet_water_fahrenheit * t_source_fahrenheit))
|
||||
cop_curve_coefficients[5] * t_inlet_water_fahrenheit * t_source_fahrenheit)) / 3.41214
|
||||
hp_efficiency = float(self.hp.cooling_efficiency)
|
||||
else:
|
||||
if self.hp.heat_efficiency_curve is not None:
|
||||
|
|
|
@ -59,12 +59,15 @@ class HeatPumpCooling:
|
|||
hp_electricity[i] = 0
|
||||
hp_electricity_j = [(x * cte.WATTS_HOUR_TO_JULES) / number_of_ts for x in hp_electricity]
|
||||
hp_hourly = []
|
||||
hp_supply_temperature_hourly = []
|
||||
hp_sum = 0
|
||||
for i in range(1, len(demand)):
|
||||
hp_sum += hp_electricity_j[i]
|
||||
if (i - 1) % number_of_ts == 0:
|
||||
hp_hourly.append(hp_sum)
|
||||
hp_supply_temperature_hourly.append(t_sup_hp[i])
|
||||
hp_sum = 0
|
||||
self.hp.cooling_supply_temperature = hp_supply_temperature_hourly
|
||||
self.hp.energy_consumption[cte.COOLING] = {}
|
||||
self.hp.energy_consumption[cte.COOLING][cte.HOUR] = hp_hourly
|
||||
self.hp.energy_consumption[cte.COOLING][cte.MONTH] = MonthlyValues.get_total_month(
|
||||
|
@ -73,7 +76,7 @@ class HeatPumpCooling:
|
|||
sum(self.hp.energy_consumption[cte.COOLING][cte.MONTH])]
|
||||
self.results['Cooling Demand (W)'] = demand
|
||||
self.results['HP Cooling Output (W)'] = q_hp
|
||||
self.results['HP Source Temperature'] = source_temperature
|
||||
self.results['HP Cooling Source Temperature'] = source_temperature
|
||||
self.results['HP Cooling Supply Temperature'] = t_sup_hp
|
||||
self.results['HP Cooling COP'] = hp_cop
|
||||
self.results['HP Electricity Consumption'] = hp_electricity
|
||||
|
|
|
@ -8,8 +8,8 @@ from energy_system_modelling_package.energy_system_modelling_factories.montreal_
|
|||
|
||||
|
||||
class HeuristicSizing:
|
||||
def __init__(self, city, population_size=100, generations=50, crossover_rate=0.8, mutation_rate=0.1,
|
||||
optimization_scenario='cost', output_path=None):
|
||||
def __init__(self, city, population_size=100, generations=20, crossover_rate=0.8, mutation_rate=0.1,
|
||||
optimization_scenario='energy', output_path=None):
|
||||
self.city = city
|
||||
self.population_size = population_size
|
||||
self.generations = generations
|
||||
|
@ -20,13 +20,24 @@ class HeuristicSizing:
|
|||
|
||||
# Main Genetic Algorithm function
|
||||
def genetic_algorithm(self):
|
||||
best_individuals = []
|
||||
min_fitness_scores = []
|
||||
city_best_individuals = []
|
||||
building_best_individuals = []
|
||||
best_fitness_score = float('inf')
|
||||
best_solution = None
|
||||
best_solution_generation = 0
|
||||
for building in self.city.buildings:
|
||||
print(building.name)
|
||||
population = self.initialize_population(building)
|
||||
for generation in range(self.generations):
|
||||
print(generation)
|
||||
fitness_scores = self.evaluate_population(building, population)
|
||||
population = sorted(population, key=lambda x: x['fitness_score'])
|
||||
building_best_individuals.append(population[0])
|
||||
if population[0]['fitness_score'] < best_fitness_score:
|
||||
best_fitness_score_index = fitness_scores.index(population[0]['fitness_score'])
|
||||
best_fitness_score = fitness_scores[best_fitness_score_index]
|
||||
best_solution = population[0]
|
||||
best_solution_generation = generation
|
||||
selected_population = self.tournament_selection(population, fitness_scores)
|
||||
next_population = []
|
||||
for i in range(0, self.population_size, 2):
|
||||
|
@ -34,14 +45,10 @@ class HeuristicSizing:
|
|||
child1, child2 = self.crossover(parent1, parent2)
|
||||
next_population.extend([self.mutate(child1, building), self.mutate(child2, building)])
|
||||
population = next_population
|
||||
# # Evaluate final population
|
||||
fitness_scores = self.evaluate_population(building, population)
|
||||
best_index = fitness_scores.index(min(fitness_scores))
|
||||
best_individual = population[best_index]
|
||||
best_individuals.append(best_individual)
|
||||
min_fitness_scores.append(min(fitness_scores))
|
||||
print("best individuals are", best_individuals)
|
||||
return best_individuals, min_fitness_scores
|
||||
print(f"best individual of {building.name} is ", best_solution, "It is found in generation:",
|
||||
best_solution_generation)
|
||||
city_best_individuals.append(best_solution)
|
||||
return city_best_individuals
|
||||
|
||||
@staticmethod
|
||||
def system_components(building):
|
||||
|
@ -56,14 +63,14 @@ class HeuristicSizing:
|
|||
for generation_system in energy_system.generation_systems:
|
||||
system_components[cte.HEATING]['generation_components'].append({'type': generation_system.system_type,
|
||||
'efficiency':
|
||||
generation_system.heat_efficiency,
|
||||
generation_system.heat_efficiency,
|
||||
'capacity': 0})
|
||||
if generation_system.energy_storage_systems is not None:
|
||||
system_components[cte.HEATING]['storage_components'] = []
|
||||
for storage_system in generation_system.energy_storage_systems:
|
||||
if storage_system.type_energy_stored == cte.THERMAL:
|
||||
system_components[cte.HEATING]['storage_components'].append({'storage_type':
|
||||
storage_system.type_energy_stored,
|
||||
storage_system.type_energy_stored,
|
||||
'volume': 0})
|
||||
if cte.COOLING in energy_system.demand_types:
|
||||
system_components[cte.COOLING] = {'generation_components': []}
|
||||
|
@ -71,14 +78,14 @@ class HeuristicSizing:
|
|||
if generation_system.fuel_type == cte.ELECTRICITY:
|
||||
system_components[cte.COOLING]['generation_components'].append({'type': generation_system.system_type,
|
||||
'efficiency':
|
||||
generation_system.cooling_efficiency,
|
||||
generation_system.cooling_efficiency,
|
||||
'capacity': 0})
|
||||
if generation_system.energy_storage_systems is not None:
|
||||
system_components[cte.COOLING]['storage_components'] = []
|
||||
for storage_system in generation_system.energy_storage_systems:
|
||||
if storage_system.type_energy_stored == cte.THERMAL:
|
||||
system_components[cte.COOLING]['storage_components'].append({'storage_type':
|
||||
storage_system.type_energy_stored,
|
||||
storage_system.type_energy_stored,
|
||||
'volume': 0})
|
||||
if cte.DOMESTIC_HOT_WATER in energy_system.demand_types and cte.HEATING not in energy_system.demand_types:
|
||||
system_components[cte.DOMESTIC_HOT_WATER] = {'generation_components': []}
|
||||
|
@ -93,7 +100,7 @@ class HeuristicSizing:
|
|||
for storage_system in generation_system.energy_storage_systems:
|
||||
if storage_system.type_energy_stored == cte.THERMAL:
|
||||
system_components[cte.DOMESTIC_HOT_WATER]['storage_components'].append({'storage_type':
|
||||
storage_system.type_energy_stored,
|
||||
storage_system.type_energy_stored,
|
||||
'volume': 0})
|
||||
return system_components
|
||||
|
||||
|
@ -146,42 +153,41 @@ class HeuristicSizing:
|
|||
if self.optimization_scenario == 'cost':
|
||||
lcc = self.life_cycle_cost(building, population)
|
||||
fitness_scores = lcc
|
||||
elif self.optimization_scenario == 'energy':
|
||||
energy_consumption = self.energy_consumption(building, population)
|
||||
fitness_scores = energy_consumption
|
||||
return fitness_scores
|
||||
|
||||
# Selection (Tournament Selection)
|
||||
@staticmethod
|
||||
def tournament_selection(population, fitness_scores):
|
||||
selected = []
|
||||
for _ in range(len(population)):
|
||||
i, j = random.sample(range(len(population)), 2)
|
||||
# Append a deep copy to avoid modifying the original individual
|
||||
if fitness_scores[i] < fitness_scores[j]:
|
||||
selected.append(copy.deepcopy(population[i]))
|
||||
else:
|
||||
selected.append(copy.deepcopy(population[j]))
|
||||
return selected
|
||||
|
||||
# Crossover (Uniform Crossover)
|
||||
def crossover(self, parent1, parent2):
|
||||
if random.random() < self.crossover_rate:
|
||||
child1, child2 = copy.deepcopy(parent1), copy.deepcopy(parent2)
|
||||
for key in parent1:
|
||||
if random.random() < 0.5:
|
||||
child1[key], child2[key] = child2[key], child1[key]
|
||||
if key != 'fitness_score':
|
||||
if random.random() < 0.5:
|
||||
child1[key], child2[key] = child2[key], child1[key]
|
||||
return child1, child2
|
||||
else:
|
||||
return copy.deepcopy(parent1), copy.deepcopy(parent2)
|
||||
|
||||
# Mutation
|
||||
def mutate(self, individual, building):
|
||||
"""
|
||||
Mutates the individual's generation and storage components.
|
||||
- `individual`: the individual to mutate (contains generation and storage components).
|
||||
- `building`: building data that contains constraints such as peak heating load and available space.
|
||||
"""
|
||||
# Mutate generation components
|
||||
for key in individual:
|
||||
if key != 'lcc':
|
||||
if key != 'fitness_score':
|
||||
for generation_component in individual[key]['generation_components']:
|
||||
if random.random() < self.mutation_rate:
|
||||
if key == cte.HEATING:
|
||||
|
@ -197,40 +203,46 @@ class HeuristicSizing:
|
|||
if 'storage_components' in individual[key]:
|
||||
for storage_component in individual[key]['storage_components']:
|
||||
if storage_component['storage_type'] == cte.THERMAL and random.random() < self.mutation_rate:
|
||||
# Mutate the 'volume' within the available space in the building
|
||||
max_available_space = 0.01 * building.volume / building.storeys_above_ground
|
||||
storage_component['volume'] = random.uniform(0, max_available_space)
|
||||
# for generation_component in individual['generation_components']:
|
||||
# if random.random() < self.mutation_rate:
|
||||
# # Mutate the 'capacity' within the range of 0 to the building's peak heating load
|
||||
# generation_component['capacity'] = random.uniform(0, building.heating_peak_load[cte.YEAR][0])
|
||||
#
|
||||
# # Mutate storage components
|
||||
# for storage_component in individual['storage_components']:
|
||||
# if storage_component['storage_type'] == cte.THERMAL and random.random() < self.mutation_rate:
|
||||
# # Mutate the 'volume' within the available space in the building
|
||||
# max_available_space = 0.01 * building.volume / building.storeys_above_ground
|
||||
# storage_component['volume'] = random.uniform(0, max_available_space)
|
||||
|
||||
return individual
|
||||
|
||||
def life_cycle_cost(self, building, population):
|
||||
costs = []
|
||||
for individual in population:
|
||||
self.run_system_archetype_simulation(building, individual)
|
||||
cost_retrofit_scenario = SYSTEM_RETROFIT
|
||||
lcc_dataframe = Cost(building=building,
|
||||
retrofit_scenario=cost_retrofit_scenario,
|
||||
fuel_tariffs=['Electricity-D', 'Gas-Energir']).life_cycle
|
||||
total_lcc = (lcc_dataframe.loc['total_capital_costs_systems', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['total_operational_costs', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['total_maintenance_costs', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['end_of_life_costs', f'Scenario {cost_retrofit_scenario}'])
|
||||
individual['lcc'] = total_lcc
|
||||
costs.append(total_lcc)
|
||||
individual_feasibility = self.run_system_archetype_simulation(building, individual)
|
||||
if individual_feasibility:
|
||||
cost_retrofit_scenario = SYSTEM_RETROFIT
|
||||
lcc_dataframe = Cost(building=building,
|
||||
retrofit_scenario=cost_retrofit_scenario,
|
||||
fuel_tariffs=['Electricity-D', 'Gas-Energir']).life_cycle
|
||||
total_lcc = (lcc_dataframe.loc['total_capital_costs_systems', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['total_operational_costs', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['total_maintenance_costs', f'Scenario {cost_retrofit_scenario}'] +
|
||||
lcc_dataframe.loc['end_of_life_costs', f'Scenario {cost_retrofit_scenario}'])
|
||||
individual['fitness_score'] = total_lcc
|
||||
costs.append(total_lcc)
|
||||
else:
|
||||
individual['fitness_score'] = float('inf')
|
||||
costs.append(float('inf'))
|
||||
return costs
|
||||
|
||||
def energy_consumption(self, building, population):
|
||||
total_consumptions = []
|
||||
for individual in population:
|
||||
individual_feasibility = self.run_system_archetype_simulation(building, individual)
|
||||
if individual_feasibility:
|
||||
total_consumption = (building.heating_consumption[cte.YEAR][0] + building.cooling_consumption[cte.YEAR][0] +
|
||||
building.domestic_hot_water_consumption[cte.YEAR][0])/ (cte.WATTS_HOUR_TO_JULES * 1000)
|
||||
individual['fitness_score'] = total_consumption
|
||||
total_consumptions.append(total_consumption)
|
||||
else:
|
||||
individual['fitness_score'] = float('inf')
|
||||
total_consumptions.append(float('inf'))
|
||||
return total_consumptions
|
||||
|
||||
def run_system_archetype_simulation(self, building, individual):
|
||||
feasibility = True
|
||||
if building.energy_systems_archetype_cluster_id == '1':
|
||||
building.energy_systems[1].generation_systems[0].nominal_heat_output = \
|
||||
individual[cte.HEATING]['generation_components'][0]['capacity']
|
||||
|
@ -249,13 +261,19 @@ class HeuristicSizing:
|
|||
building=building,
|
||||
output_path=self.output_path,
|
||||
csv_output=False).enrich()
|
||||
if min(building.energy_systems[1].generation_systems[0].energy_storage_systems[0].temperature) < 35:
|
||||
feasibility = False
|
||||
if min(building.energy_systems[-1].generation_systems[0].energy_storage_systems[0].temperature) < 55:
|
||||
feasibility = False
|
||||
if max(building.energy_systems[1].generation_systems[1].cooling_supply_temperature) > 16:
|
||||
feasibility = False
|
||||
return feasibility
|
||||
|
||||
def enrich_buildings(self):
|
||||
best_individuals, best_fitness_scores = self.genetic_algorithm()
|
||||
best_individuals = self.genetic_algorithm()
|
||||
for (i, building) in enumerate(self.city.buildings):
|
||||
energy_systems = building.energy_systems
|
||||
best_individual = best_individuals[i]
|
||||
# best_fitness_score = best_fitness_scores[i]
|
||||
for energy_system in energy_systems:
|
||||
if cte.HEATING in energy_system.demand_types:
|
||||
for generation_system in energy_system.generation_systems:
|
||||
|
@ -275,7 +293,7 @@ class HeuristicSizing:
|
|||
for generation_component in best_individual[cte.COOLING]['generation_components']:
|
||||
if generation_component['type'] == system_type:
|
||||
generation_system.nominal_cooling_output = generation_component['capacity']
|
||||
if generation_system.energy_storage_systems is not None:
|
||||
if generation_system.energy_storage_systems is not None and generation_system.fuel_type == cte.ELECTRICITY:
|
||||
for storage_system in generation_system.energy_storage_systems:
|
||||
storage_type = storage_system.type_energy_stored
|
||||
for storage_component in best_individual[cte.COOLING]['storage_components']:
|
||||
|
@ -293,4 +311,3 @@ class HeuristicSizing:
|
|||
for storage_component in best_individual[cte.DOMESTIC_HOT_WATER]['storage_components']:
|
||||
if storage_component['storage_type'] == storage_type:
|
||||
storage_system.volume = storage_component['volume']
|
||||
|
||||
|
|
|
@ -474,7 +474,7 @@ class NonPvGenerationSystem(GenerationSystem):
|
|||
Get the hourly cooling supply temperature
|
||||
:return: list
|
||||
"""
|
||||
return self._heat_supply_temperature
|
||||
return self._cooling_supply_temperature
|
||||
|
||||
@cooling_supply_temperature.setter
|
||||
def cooling_supply_temperature(self, value):
|
||||
|
|
|
@ -109,16 +109,16 @@ class ThermalStorageSystem(EnergyStorageSystem):
|
|||
@property
|
||||
def temperature(self) -> dict:
|
||||
"""
|
||||
Get fuel consumption in W, m3, or kg
|
||||
:return: dict{[float]}
|
||||
Get hourly storage temperature in degree Celsius
|
||||
:return: list
|
||||
"""
|
||||
return self._temperature
|
||||
|
||||
@temperature.setter
|
||||
def temperature(self, value):
|
||||
"""
|
||||
Set fuel consumption in W, m3, or kg
|
||||
:param value: dict{[float]}
|
||||
Set hourly storage temperature in degree Celsius
|
||||
:param value: list
|
||||
"""
|
||||
self._temperature = value
|
||||
|
||||
|
|
|
@ -912,7 +912,7 @@
|
|||
<nominal_cooling_output/>
|
||||
<minimum_cooling_output/>
|
||||
<maximum_cooling_output/>
|
||||
<cooling_efficiency>4</cooling_efficiency>
|
||||
<cooling_efficiency>4.5</cooling_efficiency>
|
||||
<electricity_efficiency/>
|
||||
<source_temperature/>
|
||||
<source_mass_flow/>
|
||||
|
|
5
main.py
5
main.py
|
@ -51,12 +51,13 @@ energy_plus_workflow(city, energy_plus_output_path)
|
|||
random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage)
|
||||
EnergySystemsFactory('montreal_future', city).enrich()
|
||||
EnergySystemsSizingFactory('pv_sizing', city).enrich()
|
||||
EnergySystemsSizingFactory('peak_load_sizing', city).enrich()
|
||||
# EnergySystemsSizingFactory('heuristic_sizing', city).enrich()
|
||||
# EnergySystemsSizingFactory('peak_load_sizing', city).enrich()
|
||||
EnergySystemsSizingFactory('heuristic_sizing', city).enrich()
|
||||
for building in city.buildings:
|
||||
MontrealEnergySystemArchetypesSimulationFactory(f'archetype_cluster_{building.energy_systems_archetype_cluster_id}',
|
||||
building,
|
||||
simulation_results_path).enrich()
|
||||
print('test')
|
||||
# retrofitted_energy_consumption = consumption_data(city)
|
||||
# retrofitted_life_cycle_cost = {}
|
||||
# for building in city.buildings:
|
||||
|
|
Loading…
Reference in New Issue
Block a user