feat: single objective optimization started
This commit is contained in:
parent
4c3b28a088
commit
07cdfc4bf7
|
@ -10,9 +10,8 @@ from energy_system_modelling_package.energy_system_modelling_factories.system_si
|
|||
|
||||
|
||||
class GeneticAlgorithm:
|
||||
def __init__(self, city, population_size=100, generations=50, crossover_rate=0.8, mutation_rate=0.1,
|
||||
def __init__(self, population_size=100, generations=50, crossover_rate=0.8, mutation_rate=0.1,
|
||||
optimization_scenario='cost', output_path=None):
|
||||
self.city = city
|
||||
self.population_size = population_size
|
||||
self.generations = generations
|
||||
self.crossover_rate = crossover_rate
|
||||
|
@ -24,8 +23,11 @@ class GeneticAlgorithm:
|
|||
def energy_system_archetype_optimal_sizing(self):
|
||||
pass
|
||||
|
||||
# Initialize Population
|
||||
def initialize_population(self, energy_system):
|
||||
# Initialize Population
|
||||
def initialize_population(self, building, energy_system, heating_design_load=None, cooling_design_load=None,
|
||||
available_space=None, dt=1800, fuel_price_index=0.05, electricity_tariff_type='fixed',
|
||||
consumer_price_index=0.04, interest_rate=0.04, discount_rate=0.03, percentage_credit=0,
|
||||
credit_years=15):
|
||||
"""
|
||||
The population to optimize the sizes of generation and storage components of any energy system are optimized.
|
||||
The initial population will be a list of individuals where each of them represent a possible solution to the
|
||||
|
@ -35,21 +37,28 @@ class GeneticAlgorithm:
|
|||
"""
|
||||
population = []
|
||||
for i in range(self.population_size):
|
||||
population.append(Individual(energy_system, self.optimization_scenario))
|
||||
population.append(Individual(building, energy_system, self.optimization_scenario,
|
||||
heating_design_load=heating_design_load, cooling_design_load=cooling_design_load,
|
||||
available_space=available_space, dt=dt, fuel_price_index=fuel_price_index,
|
||||
electricity_tariff_type=electricity_tariff_type,
|
||||
consumer_price_index=consumer_price_index, interest_rate=interest_rate,
|
||||
discount_rate=discount_rate, percentage_credit=percentage_credit,
|
||||
credit_years=credit_years))
|
||||
return population
|
||||
|
||||
def solve_ga(self, energy_system):
|
||||
def solve_ga(self, building, energy_system):
|
||||
"""
|
||||
Solving GA for a single energy system. Here are the steps:
|
||||
1- Population is initialized using the "initialize_population" method in this class.
|
||||
:param building:
|
||||
:param energy_system:
|
||||
:return:
|
||||
"""
|
||||
energy_system = energy_system
|
||||
best_individuals = []
|
||||
best_solution = None
|
||||
population = self.initialize_population(energy_system)
|
||||
|
||||
|
||||
|
||||
|
||||
population = self.initialize_population(building, energy_system)
|
||||
for individual in population:
|
||||
individual.score_evaluation()
|
||||
print(individual.individual['feasible'])
|
||||
print(individual.individual['fitness_score'])
|
||||
|
|
|
@ -12,9 +12,9 @@ import numpy_financial as npf
|
|||
|
||||
class Individual:
|
||||
def __init__(self, building, energy_system, optimization_scenario, heating_design_load=None,
|
||||
cooling_design_load=None, available_space=None, dt=1800, fuel_price_index=0.05,
|
||||
electricity_tariff_type='fixed', consumer_price_index=0.04, interest_rate=0.04,
|
||||
discount_rate=0.03, percentage_credit=0, credit_years=15):
|
||||
cooling_design_load=None, available_space=None, dt=None, fuel_price_index=None,
|
||||
electricity_tariff_type='fixed', consumer_price_index=None, interest_rate=None,
|
||||
discount_rate=None, percentage_credit=None, credit_years=None):
|
||||
"""
|
||||
:param building: building object
|
||||
:param energy_system: energy system to be optimized
|
||||
|
@ -95,10 +95,12 @@ class Individual:
|
|||
f'{energy_storage_system.type_energy_stored}_storage'))
|
||||
if energy_storage_system.type_energy_stored == cte.THERMAL:
|
||||
heating_coil_capacity = energy_storage_system.heating_coil_capacity
|
||||
heating_coil_fuel_cost = self.fuel_cost_per_kwh(f'{cte.ELECTRICITY}', 'fixed')
|
||||
volume = 0
|
||||
capacity = None
|
||||
else:
|
||||
heating_coil_capacity = None
|
||||
heating_coil_fuel_cost = None
|
||||
volume = None
|
||||
capacity = 0
|
||||
self.individual['Energy Storage Components'].append(
|
||||
|
@ -108,6 +110,7 @@ class Individual:
|
|||
'heating_coil_capacity': heating_coil_capacity,
|
||||
'unit_investment_cost': investment_cost,
|
||||
'unit_reposition_cost': reposition_cost,
|
||||
'heating_coil_fuel_cost': heating_coil_fuel_cost,
|
||||
'unit_maintenance_cost': 0,
|
||||
'lifetime': lifetime
|
||||
})
|
||||
|
@ -122,12 +125,18 @@ class Individual:
|
|||
generation_components = self.individual['Generation Components']
|
||||
storage_components = self.individual['Energy Storage Components']
|
||||
for generation_component in generation_components:
|
||||
if generation_component['nominal_heating_efficiency'] is not None and self.heating_design_load is not None:
|
||||
generation_component['heating_capacity'] = random.uniform(0, self.heating_design_load)
|
||||
if generation_component['nominal_heating_efficiency'] is not None:
|
||||
if self.heating_design_load is not None:
|
||||
generation_component['heating_capacity'] = random.uniform(0, self.heating_design_load)
|
||||
else:
|
||||
generation_component['heating_capacity'] = random.uniform(0, self.building.heating_peak_load[cte.YEAR][0])
|
||||
else:
|
||||
generation_component['heating_capacity'] = None
|
||||
if generation_component['nominal_cooling_efficiency'] is not None and self.cooling_design_load is not None:
|
||||
generation_component['cooling_capacity'] = random.uniform(0, self.cooling_design_load)
|
||||
if generation_component['nominal_cooling_efficiency'] is not None:
|
||||
if self.cooling_design_load is not None:
|
||||
generation_component['cooling_capacity'] = random.uniform(0, self.cooling_design_load)
|
||||
else:
|
||||
generation_component['cooling_capacity'] = random.uniform(0, self.building.cooling_peak_load[cte.YEAR][0])
|
||||
else:
|
||||
generation_component['cooling_capacity'] = None
|
||||
if generation_component['nominal_electricity_efficiency'] is None:
|
||||
|
@ -135,12 +144,15 @@ class Individual:
|
|||
for storage_component in storage_components:
|
||||
if storage_component['type'] == f'{cte.THERMAL}_storage':
|
||||
storage_component['volume'] = random.uniform(0, 0.01 * self.available_space)
|
||||
if storage_component['heating_coil_capacity'] is not None:
|
||||
storage_component['heating_coil_capacity'] = random.uniform(0, self.heating_design_load)
|
||||
|
||||
def score_evaluation(self):
|
||||
self.initialization()
|
||||
self.system_simulation()
|
||||
self.individual['feasible'] = self.feasibility
|
||||
if self.feasibility:
|
||||
if self.optimization_scenario == 'cost':
|
||||
if 'cost' in self.optimization_scenario:
|
||||
investment_cost = 0
|
||||
operation_cost_year_0 = 0
|
||||
maintenance_cost_year_0 = 0
|
||||
|
@ -157,17 +169,27 @@ class Individual:
|
|||
for storage_system in self.individual['Energy Storage Components']:
|
||||
if cte.THERMAL in storage_system['type']:
|
||||
investment_cost += storage_system['volume'] * storage_system['unit_investment_cost']
|
||||
if storage_system['heating_coil_capacity'] is not None:
|
||||
operation_cost_year_0 += (storage_system['yearly_energy_consumption(kWh)'] *
|
||||
storage_system['heating_coil_fuel_cost'])
|
||||
lcc = self.life_cycle_cost_calculation(investment_cost=investment_cost,
|
||||
operation_cost_year_0=operation_cost_year_0,
|
||||
maintenance_cost_year_0=maintenance_cost_year_0)
|
||||
self.individual['fitness score'] = lcc
|
||||
elif self.optimization_scenario == 'energy_consumption':
|
||||
pass
|
||||
self.individual['lcc'] = lcc
|
||||
self.individual['fitness_score'] = lcc
|
||||
elif 'energy_consumption' in self.optimization_scenario:
|
||||
total_energy_consumption = 0
|
||||
for generation_system in self.individual['Generation Components']:
|
||||
total_energy_consumption += generation_system['yearly_energy_consumption(kWh)']
|
||||
for storage_system in self.individual['Energy Storage Components']:
|
||||
if cte.THERMAL in storage_system['type'] and storage_system['heating_coil_capacity'] is not None:
|
||||
total_energy_consumption += storage_system['yearly_energy_consumption(kWh)']
|
||||
self.individual['total_energy_consumption'] = total_energy_consumption
|
||||
self.individual['fitness_score'] = total_energy_consumption
|
||||
elif self.optimization_scenario == 'cost_energy_consumption':
|
||||
pass
|
||||
else:
|
||||
self.individual['fitness score'] = float('inf')
|
||||
print(self.individual)
|
||||
self.individual['fitness_score'] = float('inf')
|
||||
|
||||
def system_simulation(self):
|
||||
"""
|
||||
|
@ -183,9 +205,12 @@ class Individual:
|
|||
hp.nominal_heat_output = self.individual['Generation Components'][1]['heating_capacity']
|
||||
tes = self.energy_system.generation_systems[0].energy_storage_systems[0]
|
||||
tes.volume = self.individual['Energy Storage Components'][0]['volume']
|
||||
tes.height = self.building.average_storey_height - 1.5
|
||||
tes.height = self.building.average_storey_height - 1
|
||||
tes.heating_coil_capacity = self.individual['Energy Storage Components'][0]['heating_coil_capacity'] \
|
||||
if self.individual['Energy Storage Components'][0]['heating_coil_capacity'] is not None else 0
|
||||
heating_demand_joules = self.building.heating_demand[cte.HOUR]
|
||||
heating_peak_load_watts = self.heating_design_load
|
||||
heating_peak_load_watts = self.heating_design_load if (self.heating_design_load is not
|
||||
None) else self.building.heating_peak_load[cte.YEAR][0]
|
||||
upper_limit_tes_heating = 55
|
||||
outdoor_temperature = self.building.external_temperature[cte.HOUR]
|
||||
results = HeatPumpBoilerTesHeating(hp=hp,
|
||||
|
@ -200,7 +225,12 @@ class Individual:
|
|||
self.feasibility = False
|
||||
elif cte.DOMESTIC_HOT_WATER in self.demand_types:
|
||||
hp = self.energy_system.generation_systems[0]
|
||||
hp.nominal_heat_output = self.individual['Generation Components'][0]['heating_capacity']
|
||||
tes = self.energy_system.generation_systems[0].energy_storage_systems[0]
|
||||
tes.volume = self.individual['Energy Storage Components'][0]['volume']
|
||||
tes.height = self.building.average_storey_height - 1
|
||||
tes.heating_coil_capacity = self.individual['Energy Storage Components'][0]['heating_coil_capacity'] \
|
||||
if self.individual['Energy Storage Components'][0]['heating_coil_capacity'] is not None else 0
|
||||
dhw_demand_joules = self.building.domestic_hot_water_heat_demand[cte.HOUR]
|
||||
upper_limit_tes = 65
|
||||
outdoor_temperature = self.building.external_temperature[cte.HOUR]
|
||||
|
@ -218,8 +248,80 @@ class Individual:
|
|||
for generation_component in self.individual['Generation Components']:
|
||||
if generation_component['type'] in generation_system_types:
|
||||
index = generation_system_types.index(generation_component['type'])
|
||||
generation_component['yearly_energy_consumption(kWh)'] = (
|
||||
self.energy_system.generation_systems[index].energy_consumption[cte.HEATING][cte.YEAR][0] / 3.6e6)
|
||||
for demand_type in self.demand_types:
|
||||
if demand_type in self.energy_system.generation_systems[index].energy_consumption:
|
||||
generation_component['yearly_energy_consumption(kWh)'] = (
|
||||
self.energy_system.generation_systems[index].energy_consumption[demand_type][cte.YEAR][0] / 3.6e6)
|
||||
for storage_component in self.individual['Energy Storage Components']:
|
||||
if storage_component['type'] == f'{cte.THERMAL}_storage' and storage_component[
|
||||
'heating_coil_capacity'] is not None:
|
||||
for generation_system in self.energy_system.generation_systems:
|
||||
if generation_system.energy_storage_systems is not None:
|
||||
for storage_system in generation_system.energy_storage_systems:
|
||||
if storage_system.type_energy_stored == cte.THERMAL:
|
||||
for demand_type in self.demand_types:
|
||||
if demand_type in storage_system.heating_coil_energy_consumption:
|
||||
storage_component['yearly_energy_consumption(kWh)'] = (
|
||||
storage_system.heating_coil_energy_consumption[demand_type][cte.YEAR][0] / 3.6e6)
|
||||
|
||||
def life_cycle_cost_calculation(self, investment_cost, operation_cost_year_0, maintenance_cost_year_0,
|
||||
life_cycle_duration=41):
|
||||
"""
|
||||
Calculating the life cycle cost of the energy system. The original cost workflow in hub is not used to reduce
|
||||
computation time.Here are the steps:
|
||||
1- Costs catalog and different components are imported.
|
||||
2- Capital costs (investment and reposition) are calculated and appended to a list to have the capital cash
|
||||
flow.
|
||||
3-
|
||||
:param maintenance_cost_year_0:
|
||||
:param operation_cost_year_0:
|
||||
:param investment_cost:
|
||||
:param life_cycle_duration:
|
||||
:return:
|
||||
"""
|
||||
capital_costs_cash_flow = [investment_cost]
|
||||
operational_costs_cash_flow = [0]
|
||||
maintenance_costs_cash_flow = [0]
|
||||
end_of_life_costs = [0] * (life_cycle_duration + 1)
|
||||
for i in range(1, life_cycle_duration + 1):
|
||||
yearly_operational_cost = math.pow(1 + self.fuel_price_index, i) * operation_cost_year_0
|
||||
yearly_maintenance_cost = math.pow(1 + self.consumer_price_index, i) * maintenance_cost_year_0
|
||||
yearly_capital_cost = 0
|
||||
for generation_system in self.individual['Generation Components']:
|
||||
if (i % generation_system['lifetime']) == 0 and i != (life_cycle_duration - 1):
|
||||
cost_increase = math.pow(1 + self.consumer_price_index, i)
|
||||
heating_capacity = 0 if generation_system['heating_capacity'] is None else generation_system[
|
||||
'heating_capacity']
|
||||
cooling_capacity = 0 if generation_system['cooling_capacity'] is None else generation_system[
|
||||
'cooling_capacity']
|
||||
capacity = max(heating_capacity, cooling_capacity)
|
||||
yearly_capital_cost += generation_system['unit_reposition_cost'] * capacity * cost_increase / 1000
|
||||
yearly_capital_cost += -npf.pmt(self.interest_rate, self.credit_years,
|
||||
investment_cost * self.percentage_credit)
|
||||
for storage_system in self.individual['Energy Storage Components']:
|
||||
if (i % storage_system['lifetime']) == 0 and i != (life_cycle_duration - 1):
|
||||
cost_increase = math.pow(1 + self.consumer_price_index, i)
|
||||
capacity = storage_system['volume'] if cte.THERMAL in storage_system['type'] else storage_system['capacity']
|
||||
yearly_capital_cost += storage_system['unit_reposition_cost'] * capacity * cost_increase
|
||||
yearly_capital_cost += -npf.pmt(self.interest_rate, self.credit_years,
|
||||
investment_cost * self.percentage_credit)
|
||||
capital_costs_cash_flow.append(yearly_capital_cost)
|
||||
operational_costs_cash_flow.append(yearly_operational_cost)
|
||||
maintenance_costs_cash_flow.append(yearly_maintenance_cost)
|
||||
for year in range(1, life_cycle_duration + 1):
|
||||
price_increase = math.pow(1 + self.consumer_price_index, year)
|
||||
if year == life_cycle_duration:
|
||||
end_of_life_costs[year] = (
|
||||
self.building.thermal_zones_from_internal_zones[0].total_floor_area *
|
||||
self.individual['End of Life Cost'] * price_increase
|
||||
)
|
||||
|
||||
life_cycle_capital_cost = npf.npv(self.discount_rate, capital_costs_cash_flow)
|
||||
life_cycle_operational_cost = npf.npv(self.discount_rate, operational_costs_cash_flow)
|
||||
life_cycle_maintenance_cost = npf.npv(self.discount_rate, maintenance_costs_cash_flow)
|
||||
life_cycle_end_of_life_cost = npf.npv(self.discount_rate, end_of_life_costs)
|
||||
total_life_cycle_cost = life_cycle_capital_cost + life_cycle_operational_cost + life_cycle_maintenance_cost + life_cycle_end_of_life_cost
|
||||
return total_life_cycle_cost
|
||||
|
||||
def costs_archetype(self):
|
||||
costs_catalogue = CostsCatalogFactory('montreal_new').catalog.entries().archetypes
|
||||
|
@ -328,62 +430,3 @@ class Individual:
|
|||
conversion_factor = fuel.density[0]
|
||||
fuel_cost = fuel.variable.values[0] / (conversion_factor * fuel.lower_heating_value[0] * 0.277)
|
||||
return fuel_cost
|
||||
|
||||
def life_cycle_cost_calculation(self, investment_cost, operation_cost_year_0, maintenance_cost_year_0,
|
||||
life_cycle_duration=41):
|
||||
"""
|
||||
Calculating the life cycle cost of the energy system. The original cost workflow in hub is not used to reduce
|
||||
computation time.Here are the steps:
|
||||
1- Costs catalog and different components are imported.
|
||||
2- Capital costs (investment and reposition) are calculated and appended to a list to have the capital cash
|
||||
flow.
|
||||
3-
|
||||
:param maintenance_cost_year_0:
|
||||
:param operation_cost_year_0:
|
||||
:param investment_cost:
|
||||
:param life_cycle_duration:
|
||||
:return:
|
||||
"""
|
||||
capital_costs_cash_flow = [investment_cost]
|
||||
operational_costs_cash_flow = [0]
|
||||
maintenance_costs_cash_flow = [0]
|
||||
end_of_life_costs = [0] * (life_cycle_duration + 1)
|
||||
for i in range(1, life_cycle_duration + 1):
|
||||
yearly_operational_cost = math.pow(1 + self.fuel_price_index, i) * operation_cost_year_0
|
||||
yearly_maintenance_cost = math.pow(1 + self.consumer_price_index, i) * maintenance_cost_year_0
|
||||
yearly_capital_cost = 0
|
||||
for generation_system in self.individual['Generation Components']:
|
||||
if (i % generation_system['lifetime']) == 0 and i != (life_cycle_duration - 1):
|
||||
cost_increase = math.pow(1 + self.consumer_price_index, i)
|
||||
heating_capacity = 0 if generation_system['heating_capacity'] is None else generation_system[
|
||||
'heating_capacity']
|
||||
cooling_capacity = 0 if generation_system['cooling_capacity'] is None else generation_system[
|
||||
'cooling_capacity']
|
||||
capacity = max(heating_capacity, cooling_capacity)
|
||||
yearly_capital_cost += generation_system['unit_reposition_cost'] * capacity * cost_increase / 1000
|
||||
yearly_capital_cost += -npf.pmt(self.interest_rate, self.credit_years,
|
||||
investment_cost * self.percentage_credit)
|
||||
for storage_system in self.individual['Energy Storage Components']:
|
||||
if (i % storage_system['lifetime']) == 0 and i != (life_cycle_duration - 1):
|
||||
cost_increase = math.pow(1 + self.consumer_price_index, i)
|
||||
capacity = storage_system['volume'] if cte.THERMAL in storage_system['type'] else storage_system['capacity']
|
||||
yearly_capital_cost += storage_system['unit_reposition_cost'] * capacity * cost_increase
|
||||
yearly_capital_cost += -npf.pmt(self.interest_rate, self.credit_years,
|
||||
investment_cost * self.percentage_credit)
|
||||
capital_costs_cash_flow.append(yearly_capital_cost)
|
||||
operational_costs_cash_flow.append(yearly_operational_cost)
|
||||
maintenance_costs_cash_flow.append(yearly_maintenance_cost)
|
||||
for year in range(1, life_cycle_duration + 1):
|
||||
price_increase = math.pow(1 + self.consumer_price_index, year)
|
||||
if year == life_cycle_duration:
|
||||
end_of_life_costs[year] = (
|
||||
self.building.thermal_zones_from_internal_zones[0].total_floor_area *
|
||||
self.individual['End of Life Cost'] * price_increase
|
||||
)
|
||||
|
||||
life_cycle_capital_cost = npf.npv(self.discount_rate, capital_costs_cash_flow)
|
||||
life_cycle_operational_cost = npf.npv(self.discount_rate, operational_costs_cash_flow)
|
||||
life_cycle_maintenance_cost = npf.npv(self.discount_rate, maintenance_costs_cash_flow)
|
||||
life_cycle_end_of_life_cost = npf.npv(self.discount_rate, end_of_life_costs)
|
||||
total_life_cycle_cost = life_cycle_capital_cost + life_cycle_operational_cost + life_cycle_maintenance_cost + life_cycle_end_of_life_cost
|
||||
return total_life_cycle_cost
|
||||
|
|
|
@ -1274,7 +1274,7 @@
|
|||
<storage_type>sensible</storage_type>
|
||||
<nominal_capacity/>
|
||||
<losses_ratio/>
|
||||
<heating_coil_capacity>5000</heating_coil_capacity>
|
||||
<heating_coil_capacity>0</heating_coil_capacity>
|
||||
</templateStorages>
|
||||
</energy_storage_components>
|
||||
<materials>
|
||||
|
|
7
main.py
7
main.py
|
@ -3,8 +3,7 @@ import subprocess
|
|||
from building_modelling.ep_run_enrich import energy_plus_workflow
|
||||
from energy_system_modelling_package.energy_system_modelling_factories.montreal_energy_system_archetype_modelling_factory import \
|
||||
MontrealEnergySystemArchetypesSimulationFactory
|
||||
from energy_system_modelling_package.energy_system_modelling_factories.system_sizing_methods.genetic_algorithm.individual import \
|
||||
Individual
|
||||
from energy_system_modelling_package.energy_system_modelling_factories.system_sizing_methods.genetic_algorithm.genetic_algorithm import GeneticAlgorithm
|
||||
from hub.imports.geometry_factory import GeometryFactory
|
||||
from hub.helpers.dictionaries import Dictionaries
|
||||
from hub.imports.construction_factory import ConstructionFactory
|
||||
|
@ -58,9 +57,7 @@ for building in city.buildings:
|
|||
heating_design_load = building.heating_peak_load[cte.YEAR][0]
|
||||
cooling_design_load = building.cooling_peak_load[cte.YEAR][0]
|
||||
available_space = building.volume / building.storeys_above_ground
|
||||
Individual(building, building.energy_systems[1], optimization_scenario='cost',
|
||||
heating_design_load=heating_design_load, cooling_design_load=cooling_design_load,
|
||||
available_space=available_space, dt=3600, electricity_tariff_type='fixed').score_evaluation()
|
||||
GeneticAlgorithm(optimization_scenario='cost').solve_ga(building=building, energy_system=building.energy_systems[1])
|
||||
# EnergySystemsSizingFactory('pv_sizing', city).enrich()
|
||||
# EnergySystemsSizingFactory('peak_load_sizing', city).enrich()
|
||||
# EnergySystemsSizingFactory('heuristic_sizing', city).enrich()
|
||||
|
|
Loading…
Reference in New Issue
Block a user