feat: cost optimization of heating system is completed

This commit is contained in:
Saeed Ranjbar 2024-09-11 18:13:24 -04:00
parent 21b4fc5202
commit eee55fc453
170 changed files with 54 additions and 19 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@
cerc_hub.egg-info
/out_files
/input_files/output_buildings.geojson
*.pyc

View File

@ -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

View File

@ -8,7 +8,7 @@ from energy_system_modelling_package.energy_system_modelling_factories.montreal_
class HeuristicSizing:
def __init__(self, city, population_size=20, generations=100, crossover_rate=0.8, mutation_rate=0.1,
def __init__(self, city, population_size=4, generations=5, crossover_rate=0.8, mutation_rate=0.1,
optimization_scenario='cost', output_path=None):
self.city = city
self.population_size = population_size
@ -23,23 +23,24 @@ class HeuristicSizing:
best_individuals = []
min_fitness_scores = []
for building in self.city.buildings:
print(building.name)
population = self.initialize_population(building)
for generation in range(self.generations):
fitness_scores = self.evaluate_population(building, population)
print(f"Generation {generation}, Best Fitness: {min(fitness_scores)}")
selected_population = self.tournament_selection(population, fitness_scores)
next_population = []
for i in range(0, self.population_size, 2):
parent1, parent2 = selected_population[i], selected_population[i + 1]
child1, child2 = self.crossover(parent1, parent2)
next_population.extend([self.mutate(child1), self.mutate(child2)])
next_population.extend([self.mutate(child1, building), self.mutate(child2, building)])
population = next_population
# Evaluate final 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
@staticmethod
@ -77,6 +78,7 @@ class HeuristicSizing:
if storage_component['storage_type'] == cte.THERMAL:
max_available_space = 0.01 * building.volume / building.storeys_above_ground
storage_component['volume'] = random.uniform(0, max_available_space)
heating_system_population.append(individual_components)
return heating_system_population
@ -94,31 +96,44 @@ class HeuristicSizing:
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(population[i])
selected.append(copy.deepcopy(population[i]))
else:
selected.append(population[j])
selected.append(copy.deepcopy(population[j]))
return selected
# Crossover (Uniform Crossover)
def crossover(self, parent1, parent2):
if random.random() < self.crossover_rate:
child1, child2 = parent1[:], parent2[:]
for i in range(len(parent1)):
child1, child2 = copy.deepcopy(parent1), copy.deepcopy(parent2)
for key in parent1:
if random.random() < 0.5:
child1[i], child2[i] = child2[i], child1[i]
child1[key], child2[key] = child2[key], child1[key]
return child1, child2
else:
return parent1, parent2
return copy.deepcopy(parent1), copy.deepcopy(parent2)
# Mutation
def mutate(self, individual):
for i in range(len(individual)):
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 generation_component in individual['generation_components']:
if random.random() < self.mutation_rate:
if i == 3: # cutoff_temp
individual[i] = random.uniform(40, 60)
else:
individual[i] = random.uniform(0.1, 10.0)
# 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):
@ -153,7 +168,25 @@ class HeuristicSizing:
def enrich_buildings(self):
best_individuals, best_fitness_scores = self.genetic_algorithm()
for building in self.city.buildings:
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:
system_type = generation_system.system_type
for generation_component in best_individual['generation_components']:
if generation_component['type'] == system_type:
generation_system.nominal_heat_output = generation_component['capacity']
if generation_system.energy_storage_systems is not None:
for storage_system in generation_system.energy_storage_systems:
storage_type = storage_system.type_energy_stored
for storage_component in best_individual['storage_components']:
if storage_component['storage_type'] == storage_type:
storage_system.volume = storage_component['volume']

Some files were not shown because too many files have changed in this diff Show More