Beispiel #1
0
def evaluation_main(
    individual,
    building_names_all,
    locator,
    network_features,
    config,
    prices,
    lca,
    ind_num,
    gen,
    column_names_individual,
    column_names_buildings_heating,
    column_names_buildings_cooling,
    building_names_heating,
    building_names_cooling,
    building_names_electricity,
    district_heating_network,
    district_cooling_network,
):
    """
    This function evaluates an individual

    :param individual: list with values of the individual
    :param column_names_buildings_all: list with names of buildings
    :param locator: locator class
    :param solar_features: solar features call to class
    :param network_features: network features call to class
    :param optimization_constants: class containing constants used in optimization
    :param config: configuration file
    :param prices: class of prices used in optimization
    :type individual: list
    :type column_names_buildings_all: list
    :type locator: string
    :type solar_features: class
    :type network_features: class
    :type optimization_constants: class
    :type config: class
    :type prices: class
    :return: Resulting values of the objective function. costs, CO2, prim
    :rtype: tuple

    """

    # CREATE THE INDIVIDUAL BARCODE AND INDIVIDUAL WITH HER COLUMN NAME AS A DICT
    DHN_barcode, DCN_barcode, individual_with_name_dict, building_connectivity_dict = individual_to_barcode(
        individual, building_names_all, building_names_heating,
        building_names_cooling, column_names_individual,
        column_names_buildings_heating, column_names_buildings_cooling)

    print("EVALUATING THE NEXT SYSTEM OPTION/INDIVIDUAL")
    print(individual_with_name_dict)

    # CREATE CLASS AND PASS KEY CHARACTERISTICS OF INDIVIDUAL
    # THIS CLASS SHOULD CONTAIN ALL VARIABLES THAT MAKE AN INDIVIDUAL CONFIGURATION
    master_to_slave_vars = master.export_data_to_master_to_slave_class(
        locator, gen, ind_num, individual_with_name_dict, building_names_all,
        building_names_heating, building_names_cooling,
        building_names_electricity, DHN_barcode, DCN_barcode,
        district_heating_network, district_cooling_network)
    # INITIALIZE DICTS STORING PERFORMANCE DATA
    district_heating_fixed_costs = {}
    district_heating_generation_dispatch = {}
    district_cooling_fixed_costs = {}
    district_cooling_generation_dispatch = {}
    district_heating_capacity_installed = {}
    district_cooling_capacity_installed = {}
    # DISTRICT HEATING NETWORK
    if master_to_slave_vars.DHN_exists:
        print("DISTRICT HEATING OPERATION")
        district_heating_fixed_costs, \
        district_heating_generation_dispatch, \
        district_heating_electricity_requirements_dispatch, \
        district_heating_fuel_requirements_dispatch, \
        district_heating_capacity_installed = heating_main.district_heating_network(locator,
                                                                                    master_to_slave_vars,
                                                                                    config,
                                                                                    prices,
                                                                                    lca,
                                                                                    network_features,
                                                                                    )
    else:
        district_heating_electricity_requirements_dispatch = {
            # ENERGY REQUIREMENTS
            # Electricity
            "E_Storage_charging_req_W": np.zeros(HOURS_IN_YEAR),
            "E_Storage_discharging_req_W": np.zeros(HOURS_IN_YEAR),
            "E_DHN_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_SC_FP_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_SC_ET_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_PVT_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_Server_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_Sew_req_W": np.zeros(HOURS_IN_YEAR),
            "E_HP_Lake_req_W": np.zeros(HOURS_IN_YEAR),
            "E_GHP_req_W": np.zeros(HOURS_IN_YEAR),
            "E_BaseBoiler_req_W": np.zeros(HOURS_IN_YEAR),
            "E_PeakBoiler_req_W": np.zeros(HOURS_IN_YEAR),
            "E_BackupBoiler_req_W": np.zeros(HOURS_IN_YEAR),
        }
        district_heating_fuel_requirements_dispatch = {
            "NG_CHP_req_W": np.zeros(HOURS_IN_YEAR),
            "NG_BaseBoiler_req_W": np.zeros(HOURS_IN_YEAR),
            "NG_PeakBoiler_req_W": np.zeros(HOURS_IN_YEAR),
            "NG_BackupBoiler_req_W": np.zeros(HOURS_IN_YEAR),
            "WB_Furnace_req_W": np.zeros(HOURS_IN_YEAR),
            "DB_Furnace_req_W": np.zeros(HOURS_IN_YEAR),
        }

    # DISTRICT COOLING NETWORK:
    if master_to_slave_vars.DCN_exists:
        print("DISTRICT COOLING OPERATION")
        district_cooling_fixed_costs, \
        district_cooling_generation_dispatch, \
        district_cooling_electricity_requirements_dispatch, \
        district_cooling_fuel_requirements_dispatch, \
        district_cooling_capacity_installed = cooling_main.district_cooling_network(locator,
                                                                                    master_to_slave_vars,
                                                                                    config,
                                                                                    prices,
                                                                                    network_features)
    else:
        district_cooling_electricity_requirements_dispatch = {
            # ENERGY REQUIREMENTS
            # Electricity
            "E_DCN_req_W": np.zeros(HOURS_IN_YEAR),
            "E_BaseVCC_WS_req_W": np.zeros(HOURS_IN_YEAR),
            "E_PeakVCC_WS_req_W": np.zeros(HOURS_IN_YEAR),
            "E_BaseVCC_AS_req_W": np.zeros(HOURS_IN_YEAR),
            "E_PeakVCC_AS_req_W": np.zeros(HOURS_IN_YEAR),
            "E_BackupVCC_AS_req_W": np.zeros(HOURS_IN_YEAR),
        }
        district_cooling_fuel_requirements_dispatch = {
            "NG_Trigen_req_W": np.zeros(HOURS_IN_YEAR)
        }

    # ELECTRICITY CONSUMPTION CALCULATIONS
    print("DISTRICT ELECTRICITY GRID OPERATION")
    district_electricity_fixed_costs, \
    district_electricity_dispatch, \
    district_electricity_demands, \
    district_electricity_capacity_installed = electricity_main.electricity_calculations_of_all_buildings(locator,
                                                                                                         master_to_slave_vars,
                                                                                                         district_heating_generation_dispatch,
                                                                                                         district_heating_electricity_requirements_dispatch,
                                                                                                         district_cooling_generation_dispatch,
                                                                                                         district_cooling_electricity_requirements_dispatch)

    # print("DISTRICT NATURAL GAS / BIOMASS GRID OPERATION")
    # electricity_main.extract_fuels_demand_buildings(master_to_slave_vars, building_names_all, locator)

    print(
        "DISTRICT ENERGY SYSTEM - COSTS, PRIMARY ENERGY AND EMISSIONS OF CONNECTED BUILDINGS"
    )
    buildings_connected_costs, \
    buildings_connected_emissions = cost_model.buildings_connected_costs_and_emissions(district_heating_fixed_costs,
                                                                                       district_cooling_fixed_costs,
                                                                                       district_electricity_fixed_costs,
                                                                                       district_electricity_dispatch,
                                                                                       district_heating_fuel_requirements_dispatch,
                                                                                       district_cooling_fuel_requirements_dispatch,
                                                                                       district_electricity_demands,
                                                                                       prices,
                                                                                       lca)

    print(
        "DISTRICT ENERGY SYSTEM - COSTS, PRIMARY ENERGY AND EMISSIONS OF DISCONNECTED BUILDINGS"
    )
    buildings_disconnected_costs, \
    buildings_disconnected_emissions, \
    buildings_disconnected_heating_capacities, \
    buildings_disconnected_cooling_capacities = cost_model.buildings_disconnected_costs_and_emissions(
        building_names_heating,
        building_names_cooling,
        locator,
        master_to_slave_vars)

    print("AGGREGATING RESULTS")
    TAC_sys_USD, GHG_sys_tonCO2, PEN_sys_MJoil, performance_totals = summarize_results_individual(
        master_to_slave_vars, buildings_connected_costs,
        buildings_connected_emissions, buildings_disconnected_costs,
        buildings_disconnected_emissions)

    print("SAVING RESULTS TO DISK")
    save_results(
        master_to_slave_vars, locator, buildings_connected_costs,
        buildings_connected_emissions, buildings_disconnected_costs,
        buildings_disconnected_emissions, district_heating_generation_dispatch,
        district_cooling_generation_dispatch, district_electricity_dispatch,
        district_electricity_demands, performance_totals,
        building_connectivity_dict, district_heating_capacity_installed,
        district_cooling_capacity_installed,
        district_electricity_capacity_installed,
        buildings_disconnected_heating_capacities,
        buildings_disconnected_cooling_capacities)

    # Converting costs into float64 to avoid longer values
    print('Total TAC in USD = ' + str(TAC_sys_USD))
    print('Total GHG emissions in tonCO2-eq = ' + str(GHG_sys_tonCO2))
    print('Total PEN non-renewable in MJoil ' + str(PEN_sys_MJoil) + "\n")

    return TAC_sys_USD, GHG_sys_tonCO2, PEN_sys_MJoil
def non_dominated_sorting_genetic_algorithm(
        locator, building_names_all, district_heating_network,
        district_cooling_network, building_names_heating,
        building_names_cooling, building_names_electricity, network_features,
        config, prices, lca):
    t0 = time.clock()

    # LOCAL VARIABLES
    NGEN = config.optimization.number_of_generations  # number of generations
    NIND = config.optimization.population_size  # int(H + (4 - H % 4)) # number of individuals to select
    RANDOM_SEED = config.optimization.random_seed

    # SET-UP EVOLUTIONARY ALGORITHM
    # Hyperparameters
    # during the warmp up period we make sure we explore a wide range of solutions so the scaler works
    if NGEN < 20:
        NIND_GEN0 = 20
    else:
        NIND_GEN0 = NGEN
    NOBJ = 3  # number of objectives
    P = [2, 1]
    SCALES = [1, 0.5]
    euclidean_distance = 0
    spread = 0
    random.seed(RANDOM_SEED)
    np.random.seed(RANDOM_SEED)
    ref_points = [
        tools.uniform_reference_points(NOBJ, p, s) for p, s in zip(P, SCALES)
    ]
    ref_points = np.concatenate(ref_points)
    _, uniques = np.unique(ref_points, axis=0, return_index=True)
    ref_points = ref_points[uniques]

    # SET-UP INDIVIDUAL STRUCTURE INCLUIDING HOW EVERY POINT IS CALLED (COLUM_NAMES)
    column_names, \
    heating_unit_names_share, \
    cooling_unit_names_share, \
    column_names_buildings_heating, \
    column_names_buildings_cooling = get_column_names_individual(district_heating_network,
                                                                 district_cooling_network,
                                                                 building_names_heating,
                                                                 building_names_cooling,
                                                                 )
    individual_with_names_dict = create_empty_individual(
        column_names, column_names_buildings_heating,
        column_names_buildings_cooling, district_heating_network,
        district_cooling_network)

    # DEAP LIBRARY REFERENCE_POINT CLASSES AND TOOLS
    # reference points
    toolbox = base.Toolbox()
    toolbox.register(
        "generate",
        generate_main,
        individual_with_names_dict=individual_with_names_dict,
        column_names=column_names,
        column_names_buildings_heating=column_names_buildings_heating,
        column_names_buildings_cooling=column_names_buildings_cooling,
        district_heating_network=district_heating_network,
        district_cooling_network=district_cooling_network)
    toolbox.register("individual", tools.initIterate, creator.Individual,
                     toolbox.generate)
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    toolbox.register("mate", tools.cxUniform, indpb=CXPB)
    toolbox.register(
        "mutate",
        mutation_main,
        indpb=MUTPB,
        column_names=column_names,
        heating_unit_names_share=heating_unit_names_share,
        cooling_unit_names_share=cooling_unit_names_share,
        column_names_buildings_heating=column_names_buildings_heating,
        column_names_buildings_cooling=column_names_buildings_cooling,
        district_heating_network=district_heating_network,
        district_cooling_network=district_cooling_network)
    toolbox.register("evaluate", objective_function_wrapper)
    toolbox.register("select", tools.selNSGA3, ref_points=ref_points)

    # configure multiprocessing
    if config.multiprocessing:
        pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
        toolbox.register("map", pool.map)

    # Initialize statistics object
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("avg", np.mean, axis=0)
    stats.register("std", np.std, axis=0)
    stats.register("min", np.min, axis=0)
    stats.register("max", np.max, axis=0)

    logbook = tools.Logbook()
    logbook.header = "gen", "evals", "std", "min", "avg", "max"

    pop = toolbox.population(n=NIND_GEN0)

    # Evaluate the individuals with an invalid fitness
    invalid_ind = [ind for ind in pop if not ind.fitness.valid]
    fitnesses = toolbox.map(
        toolbox.evaluate,
        izip(invalid_ind, range(len(invalid_ind)), repeat(0, len(invalid_ind)),
             repeat(building_names_all, len(invalid_ind)),
             repeat(column_names_buildings_heating, len(invalid_ind)),
             repeat(column_names_buildings_cooling, len(invalid_ind)),
             repeat(building_names_heating, len(invalid_ind)),
             repeat(building_names_cooling, len(invalid_ind)),
             repeat(building_names_electricity, len(invalid_ind)),
             repeat(locator, len(invalid_ind)),
             repeat(network_features, len(invalid_ind)),
             repeat(config, len(invalid_ind)), repeat(prices,
                                                      len(invalid_ind)),
             repeat(lca, len(invalid_ind)),
             repeat(district_heating_network, len(invalid_ind)),
             repeat(district_cooling_network, len(invalid_ind)),
             repeat(column_names, len(invalid_ind))))

    # normalization of the first generation
    scaler_dict = scaler_for_normalization(NOBJ, fitnesses)
    fitnesses = normalize_fitnesses(scaler_dict, fitnesses)

    # add fitnesses to population individuals
    for ind, fit in zip(invalid_ind, fitnesses):
        ind.fitness.values = fit

    # Compile statistics about the population
    record = stats.compile(pop)
    logbook.record(gen=0, evals=len(invalid_ind), **record)

    print(logbook.stream)

    # Begin the generational process
    # Initialization of variables
    DHN_network_list = []
    DCN_network_list = []
    halloffame = []
    halloffame_fitness = []
    epsInd = []
    for gen in range(1, NGEN + 1):
        print("Evaluating Generation %s{} of %s{} generations", gen)
        # Select and clone the next generation individuals
        offspring = algorithms.varAnd(pop, toolbox, CXPB, MUTPB)

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = toolbox.map(
            toolbox.evaluate,
            izip(invalid_ind, range(len(invalid_ind)),
                 repeat(gen, len(invalid_ind)),
                 repeat(building_names_all, len(invalid_ind)),
                 repeat(column_names_buildings_heating, len(invalid_ind)),
                 repeat(column_names_buildings_cooling, len(invalid_ind)),
                 repeat(building_names_heating, len(invalid_ind)),
                 repeat(building_names_cooling, len(invalid_ind)),
                 repeat(building_names_electricity, len(invalid_ind)),
                 repeat(locator, len(invalid_ind)),
                 repeat(network_features, len(invalid_ind)),
                 repeat(config, len(invalid_ind)),
                 repeat(prices, len(invalid_ind)),
                 repeat(lca, len(invalid_ind)),
                 repeat(district_heating_network, len(invalid_ind)),
                 repeat(district_cooling_network, len(invalid_ind)),
                 repeat(column_names, len(invalid_ind))))
        # normalization of the second generation on
        fitnesses = normalize_fitnesses(scaler_dict, fitnesses)

        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        # Select the next generation population from parents and offspring
        pop = toolbox.select(pop + offspring, NIND)

        # Compile statistics about the new population
        record = stats.compile(pop)
        logbook.record(gen=gen, evals=len(invalid_ind), **record)
        print(logbook.stream)

        DHN_network_list_tested = []
        DCN_network_list_tested = []
        for individual in invalid_ind:
            DHN_barcode, DCN_barcode, individual_with_name_dict, _ = individual_to_barcode(
                individual, building_names_all, building_names_heating,
                building_names_cooling, column_names,
                column_names_buildings_heating, column_names_buildings_cooling)
            DCN_network_list_tested.append(DCN_barcode)
            DHN_network_list_tested.append(DHN_barcode)

        print "Save population \n"
        save_generation_dataframes(gen, invalid_ind, locator,
                                   DCN_network_list_tested,
                                   DHN_network_list_tested)
        save_generation_individuals(column_names, gen, invalid_ind, locator)

        # Create Checkpoint if necessary
        print "Create CheckPoint", gen, "\n"
        with open(locator.get_optimization_checkpoint(gen), "wb") as fp:
            cp = dict(
                selected_population=pop,
                generation=gen,
                all_population_DHN_network_barcode=DHN_network_list,
                all_population_DCN_network_barcode=DCN_network_list,
                tested_population_DHN_network_barcode=DHN_network_list_tested,
                tested_population_DCN_network_barcode=DCN_network_list_tested,
                tested_population=invalid_ind,
                tested_population_fitness=fitnesses,
                epsIndicator=epsInd,
                halloffame=halloffame,
                halloffame_fitness=halloffame_fitness,
                euclidean_distance=euclidean_distance,
                spread=spread,
                detailed_electricity_pricing=config.optimization.
                detailed_electricity_pricing,
                district_heating_network=config.optimization.
                district_heating_network,
                district_cooling_network=config.optimization.
                district_cooling_network)
            json.dump(cp, fp)

    print("save totals for generation")
    print "Master Work Complete \n"
    # print ("Number of function evaluations = " + str(function_evals))
    t1 = time.clock()
    print(t1 - t0)
    if config.multiprocessing:
        pool.close()

    return pop, logbook
def non_dominated_sorting_genetic_algorithm(locator,
                                            building_names_all,
                                            district_heating_network,
                                            district_cooling_network,
                                            building_names_heating,
                                            building_names_cooling,
                                            building_names_electricity,
                                            network_features,
                                            weather_features,
                                            config,
                                            prices,
                                            lca):
    # LOCAL VARIABLES
    NGEN = config.optimization.number_of_generations  # number of generations
    MU = config.optimization.population_size  # int(H + (4 - H % 4)) # number of individuals to select
    RANDOM_SEED = config.optimization.random_seed
    CXPB = config.optimization.crossover_prob
    MUTPB = config.optimization.mutation_prob
    technologies_heating_allowed = config.optimization.technologies_DH
    technologies_cooling_allowed = config.optimization.technologies_DC
    mutation_method_integer = config.optimization.mutation_method_integer
    mutation_method_continuous = config.optimization.mutation_method_continuous
    crossover_method_integer = config.optimization.crossover_method_integer
    crossover_method_continuous = config.optimization.crossover_method_continuous

    # SET-UP EVOLUTIONARY ALGORITHM
    # Hyperparameters
    P = 12
    ref_points = tools.uniform_reference_points(NOBJ, P)
    if MU == None:
        H = factorial(NOBJ + P - 1) / (factorial(P) * factorial(NOBJ - 1))
        MU = int(H + (4 - H % 4))
    random.seed(RANDOM_SEED)
    np.random.seed(RANDOM_SEED)

    # SET-UP INDIVIDUAL STRUCTURE INCLUIDING HOW EVERY POINT IS CALLED (COLUM_NAMES)
    column_names, \
    heating_unit_names_share, \
    cooling_unit_names_share, \
    column_names_buildings_heating, \
    column_names_buildings_cooling = get_column_names_individual(district_heating_network,
                                                                 district_cooling_network,
                                                                 building_names_heating,
                                                                 building_names_cooling,
                                                                 technologies_heating_allowed,
                                                                 technologies_cooling_allowed,

                                                                 )
    individual_with_names_dict = create_empty_individual(column_names,
                                                         column_names_buildings_heating,
                                                         column_names_buildings_cooling,
                                                         district_heating_network,
                                                         district_cooling_network,
                                                         technologies_heating_allowed,
                                                         technologies_cooling_allowed,
                                                         )

    # DEAP LIBRARY REFERENCE_POINT CLASSES AND TOOLS
    # reference points
    toolbox = base.Toolbox()
    toolbox.register("generate",
                     generate_main,
                     individual_with_names_dict=individual_with_names_dict,
                     column_names=column_names,
                     column_names_buildings_heating=column_names_buildings_heating,
                     column_names_buildings_cooling=column_names_buildings_cooling,
                     district_heating_network=district_heating_network,
                     district_cooling_network=district_cooling_network,
                     technologies_heating_allowed=technologies_heating_allowed,
                     technologies_cooling_allowed=technologies_cooling_allowed,
                     )
    toolbox.register("individual",
                     tools.initIterate,
                     creator.Individual,
                     toolbox.generate)
    toolbox.register("population",
                     tools.initRepeat,
                     list,
                     toolbox.individual)
    toolbox.register("mate",
                     crossover_main,
                     indpb=CXPB,
                     column_names=column_names,
                     heating_unit_names_share=heating_unit_names_share,
                     cooling_unit_names_share=cooling_unit_names_share,
                     column_names_buildings_heating=column_names_buildings_heating,
                     column_names_buildings_cooling=column_names_buildings_cooling,
                     district_heating_network=district_heating_network,
                     district_cooling_network=district_cooling_network,
                     technologies_heating_allowed=technologies_heating_allowed,
                     technologies_cooling_allowed=technologies_cooling_allowed,
                     crossover_method_integer=crossover_method_integer,
                     crossover_method_continuous=crossover_method_continuous)
    toolbox.register("mutate",
                     mutation_main,
                     indpb=MUTPB,
                     column_names=column_names,
                     heating_unit_names_share=heating_unit_names_share,
                     cooling_unit_names_share=cooling_unit_names_share,
                     column_names_buildings_heating=column_names_buildings_heating,
                     column_names_buildings_cooling=column_names_buildings_cooling,
                     district_heating_network=district_heating_network,
                     district_cooling_network=district_cooling_network,
                     technologies_heating_allowed=technologies_heating_allowed,
                     technologies_cooling_allowed=technologies_cooling_allowed,
                     mutation_method_integer=mutation_method_integer,
                     mutation_method_continuous=mutation_method_continuous
                     )
    toolbox.register("evaluate",
                     objective_function_wrapper)
    toolbox.register("select",
                     tools.selNSGA3WithMemory(ref_points))

    # configure multiprocessing
    if config.multiprocessing:
        pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
        toolbox.register("map", pool.map)

    # Initialize statistics object
    paretofrontier = tools.ParetoFront()
    generational_distances = []
    difference_generational_distances = []
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("avg", np.mean, axis=0)
    stats.register("std", np.std, axis=0)
    stats.register("min", np.min, axis=0)
    stats.register("max", np.max, axis=0)

    logbook = tools.Logbook()
    logbook.header = "gen", "evals", "std", "min", "avg", "max"

    pop = toolbox.population(n=MU)

    # Evaluate the individuals with an invalid fitness
    invalid_ind = [ind for ind in pop if not ind.fitness.valid]
    fitnesses = toolbox.map(toolbox.evaluate, izip(invalid_ind, range(len(invalid_ind)), repeat(0, len(invalid_ind)),
                                                   repeat(building_names_all, len(invalid_ind)),
                                                   repeat(column_names_buildings_heating, len(invalid_ind)),
                                                   repeat(column_names_buildings_cooling, len(invalid_ind)),
                                                   repeat(building_names_heating, len(invalid_ind)),
                                                   repeat(building_names_cooling, len(invalid_ind)),
                                                   repeat(building_names_electricity, len(invalid_ind)),
                                                   repeat(locator, len(invalid_ind)),
                                                   repeat(network_features, len(invalid_ind)),
                                                   repeat(weather_features, len(invalid_ind)),
                                                   repeat(config, len(invalid_ind)),
                                                   repeat(prices, len(invalid_ind)),
                                                   repeat(lca, len(invalid_ind)),
                                                   repeat(district_heating_network, len(invalid_ind)),
                                                   repeat(district_cooling_network, len(invalid_ind)),
                                                   repeat(technologies_heating_allowed, len(invalid_ind)),
                                                   repeat(technologies_cooling_allowed, len(invalid_ind)),
                                                   repeat(column_names, len(invalid_ind))))

    # normalization of the first generation
    scaler_dict = scaler_for_normalization(NOBJ, fitnesses)
    fitnesses = normalize_fitnesses(scaler_dict, fitnesses)

    # add fitnesses to population individuals
    for ind, fit in zip(invalid_ind, fitnesses):
        ind.fitness.values = fit

    # Compile statistics about the population
    record = stats.compile(pop)
    paretofrontier.update(pop)
    performance_metrics = calc_performance_metrics(0.0, paretofrontier)
    generational_distances.append(performance_metrics[0])
    difference_generational_distances.append(performance_metrics[1])
    logbook.record(gen=0, evals=len(invalid_ind), **record)

    # create a dictionary to store which individuals that are being calculated
    record_individuals_tested = {'generation': [], "individual_id": [], "individual_code": []}
    record_individuals_tested = calc_dictionary_of_all_individuals_tested(record_individuals_tested, gen=0,
                                                                          invalid_ind=invalid_ind)
    print(logbook.stream)

    # Begin the generational process
    # Initialization of variables
    for gen in range(1, NGEN + 1):
        print ("Evaluating Generation %s of %s generations" % (gen, NGEN + 1))
        # Select and clone the next generation individuals
        offspring = algorithms.varAnd(pop, toolbox, CXPB, MUTPB)

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        invalid_ind = [ind for ind in invalid_ind if ind not in pop]
        fitnesses = toolbox.map(toolbox.evaluate,
                                izip(invalid_ind, range(len(invalid_ind)), repeat(gen, len(invalid_ind)),
                                     repeat(building_names_all, len(invalid_ind)),
                                     repeat(column_names_buildings_heating, len(invalid_ind)),
                                     repeat(column_names_buildings_cooling, len(invalid_ind)),
                                     repeat(building_names_heating, len(invalid_ind)),
                                     repeat(building_names_cooling, len(invalid_ind)),
                                     repeat(building_names_electricity, len(invalid_ind)),
                                     repeat(locator, len(invalid_ind)),
                                     repeat(network_features, len(invalid_ind)),
                                     repeat(weather_features, len(invalid_ind)),
                                     repeat(config, len(invalid_ind)),
                                     repeat(prices, len(invalid_ind)),
                                     repeat(lca, len(invalid_ind)),
                                     repeat(district_heating_network, len(invalid_ind)),
                                     repeat(district_cooling_network, len(invalid_ind)),
                                     repeat(technologies_heating_allowed, len(invalid_ind)),
                                     repeat(technologies_cooling_allowed, len(invalid_ind)),
                                     repeat(column_names, len(invalid_ind))))
        # normalization of the second generation on
        fitnesses = normalize_fitnesses(scaler_dict, fitnesses)

        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        # Select the next generation population from parents and offspring
        pop = toolbox.select(pop + invalid_ind, MU)

        # get paretofront and update dictionary of individuals evaluated
        paretofrontier.update(pop)
        record_individuals_tested = calc_dictionary_of_all_individuals_tested(record_individuals_tested, gen=gen,
                                                                              invalid_ind=invalid_ind)

        # Compile statistics about the new population
        record = stats.compile(pop)
        performance_metrics = calc_performance_metrics(generational_distances[-1], paretofrontier)
        generational_distances.append(performance_metrics[0])
        difference_generational_distances.append(performance_metrics[1])
        logbook.record(gen=gen, evals=len(invalid_ind), **record)
        print(logbook.stream)

        DHN_network_list_tested = []
        DCN_network_list_tested = []
        for individual in invalid_ind:
            DHN_barcode, DCN_barcode, individual_with_name_dict, _ = individual_to_barcode(individual,
                                                                                           building_names_all,
                                                                                           building_names_heating,
                                                                                           building_names_cooling,
                                                                                           column_names,
                                                                                           column_names_buildings_heating,
                                                                                           column_names_buildings_cooling)
            DCN_network_list_tested.append(DCN_barcode)
            DHN_network_list_tested.append(DHN_barcode)

        if config.debug:
            print "Saving results for generation", gen, "\n"
            valid_generation = [gen]
            save_generation_dataframes(gen, invalid_ind, locator, DCN_network_list_tested, DHN_network_list_tested)
            save_generation_individuals(column_names, gen, invalid_ind, locator)
            systems_name_list = save_generation_pareto_individuals(locator, gen, record_individuals_tested, paretofrontier)
        else:
            systems_name_list = []
            valid_generation = []

        if gen == NGEN and config.debug == False:  # final generation re-evaluate paretofront
            print "Saving results for generation", gen, "\n"
            valid_generation = [gen]
            systems_name_list = save_final_generation_pareto_individuals(toolbox,
                                                     locator,
                                                     gen,
                                                     record_individuals_tested,
                                                     paretofrontier,
                                                     building_names_all,
                                                     column_names_buildings_heating,
                                                     column_names_buildings_cooling,
                                                     building_names_heating,
                                                     building_names_cooling,
                                                     building_names_electricity,
                                                     network_features,
                                                     weather_features,
                                                     config,
                                                     prices,
                                                     lca,
                                                     district_heating_network,
                                                     district_cooling_network,
                                                     technologies_heating_allowed,
                                                     technologies_cooling_allowed,
                                                     column_names)

        # Create Checkpoint if necessary
        print "Creating CheckPoint", gen, "\n"
        with open(locator.get_optimization_checkpoint(gen), "wb") as fp:
            cp = dict(generation=gen,
                      selected_population=pop,
                      tested_population=invalid_ind,
                      generational_distances=generational_distances,
                      difference_generational_distances = difference_generational_distances,
                      systems_to_show=systems_name_list,
                      generation_to_show =valid_generation,
                      )
            json.dump(cp, fp)
    if config.multiprocessing:
        pool.close()

    return pop, logbook
def evaluation_main(individual, building_names_all, locator, network_features,
                    weather_features, config, prices, lca, individual_number,
                    generation_number, column_names_individual,
                    column_names_buildings_heating,
                    column_names_buildings_cooling, building_names_heating,
                    building_names_cooling, building_names_electricity,
                    district_heating_network, district_cooling_network,
                    technologies_heating_allowed,
                    technologies_cooling_allowed):
    """
    This function evaluates an individual

    :param individual: list with values of the individual
    :param column_names_buildings_all: list with names of buildings
    :param cea.inputlocator.InputLocator locator: locator class
    :param solar_features: solar features call to class
    :param network_features: network features call to class
    :param optimization_constants: class containing constants used in optimization
    :param config: configuration file
    :param prices: class of prices used in optimization
    :type individual: list
    :type column_names_buildings_all: list
    :type solar_features: class
    :type network_features: class
    :type optimization_constants: class
    :type config: class
    :type prices: class
    :return: Resulting values of the objective function. costs, CO2, prim
    :rtype: tuple

    """

    # CREATE THE INDIVIDUAL BARCODE AND INDIVIDUAL WITH HER COLUMN NAME AS A DICT
    DHN_barcode, DCN_barcode, individual_with_name_dict, building_connectivity_dict = individual_to_barcode(
        individual, building_names_all, building_names_heating,
        building_names_cooling, column_names_individual,
        column_names_buildings_heating, column_names_buildings_cooling)

    print("EVALUATING THE NEXT SYSTEM OPTION/INDIVIDUAL")
    print(individual_with_name_dict)
    # CREATE CLASS AND PASS KEY CHARACTERISTICS OF INDIVIDUAL
    # THIS CLASS SHOULD CONTAIN ALL VARIABLES THAT MAKE AN INDIVIDUAL CONFIGURATION
    master_to_slave_vars = master.export_data_to_master_to_slave_class(
        locator,
        generation_number,
        individual_number,
        individual_with_name_dict,
        building_names_all,
        building_names_heating,
        building_names_cooling,
        building_names_electricity,
        DHN_barcode,
        DCN_barcode,
        district_heating_network,
        district_cooling_network,
        technologies_heating_allowed,
        technologies_cooling_allowed,
        weather_features,
    )

    # DISTRICT HEATING NETWORK
    print("DISTRICT HEATING OPERATION")
    district_heating_fixed_costs, \
    district_heating_generation_dispatch, \
    district_heating_electricity_requirements_dispatch, \
    district_heating_fuel_requirements_dispatch, \
    district_heating_capacity_installed = heating_main.district_heating_network(locator,
                                                                                master_to_slave_vars,
                                                                                config,
                                                                                network_features,
                                                                                )

    # DISTRICT COOLING NETWORK:
    print("DISTRICT COOLING OPERATION")
    district_cooling_fixed_costs, \
    district_cooling_generation_dispatch, \
    district_cooling_electricity_requirements_dispatch, \
    district_cooling_fuel_requirements_dispatch, \
    district_cooling_capacity_installed = cooling_main.district_cooling_network(locator,
                                                                                master_to_slave_vars,
                                                                                config,
                                                                                prices,
                                                                                network_features)

    # ELECTRICITY CONSUMPTION CALCULATIONS
    print("DISTRICT ELECTRICITY GRID OPERATION")
    district_electricity_fixed_costs, \
    district_electricity_dispatch, \
    district_electricity_demands, \
    district_electricity_capacity_installed = electricity_main.electricity_calculations_of_all_buildings(locator,
                                                                                                         master_to_slave_vars,
                                                                                                         district_heating_generation_dispatch,
                                                                                                         district_heating_electricity_requirements_dispatch,
                                                                                                         district_cooling_generation_dispatch,
                                                                                                         district_cooling_electricity_requirements_dispatch)

    # electricity_main.extract_fuels_demand_buildings(master_to_slave_vars, building_names_all, locator)
    print(
        "DISTRICT ENERGY SYSTEM - COSTS, PRIMARY ENERGY AND EMISSIONS OF CONNECTED BUILDINGS"
    )
    buildings_district_scale_costs, \
    buildings_district_scale_emissions = cost_model.buildings_district_scale_costs_and_emissions(district_heating_fixed_costs,
                                                                                       district_cooling_fixed_costs,
                                                                                       district_electricity_fixed_costs,
                                                                                       district_electricity_dispatch,
                                                                                       district_heating_fuel_requirements_dispatch,
                                                                                       district_cooling_fuel_requirements_dispatch,
                                                                                       district_electricity_demands,
                                                                                       prices,
                                                                                       lca)

    print(
        "DISTRICT ENERGY SYSTEM - COSTS, PRIMARY ENERGY AND EMISSIONS OF DISCONNECTED BUILDINGS"
    )
    buildings_building_scale_costs, \
    buildings_building_scale_emissions, \
    buildings_building_scale_heating_capacities, \
    buildings_building_scale_cooling_capacities = cost_model.buildings_building_scale_costs_and_emissions(
        building_names_heating,
        building_names_cooling,
        locator,
        master_to_slave_vars)

    print("AGGREGATING RESULTS")
    TAC_sys_USD, GHG_sys_tonCO2, performance_totals = summarize_results_individual(
        buildings_district_scale_costs, buildings_district_scale_emissions,
        buildings_building_scale_costs, buildings_building_scale_emissions)

    print('Total TAC in USD = ' + str(TAC_sys_USD))
    print('Total GHG emissions in tonCO2-eq = ' + str(GHG_sys_tonCO2))

    return TAC_sys_USD, \
           GHG_sys_tonCO2, \
           buildings_district_scale_costs, \
           buildings_district_scale_emissions, \
           buildings_building_scale_costs, \
           buildings_building_scale_emissions, \
           district_heating_generation_dispatch, \
           district_cooling_generation_dispatch, \
           district_electricity_dispatch, \
           district_electricity_demands, \
           performance_totals, \
           building_connectivity_dict, \
           district_heating_capacity_installed, \
           district_cooling_capacity_installed, \
           district_electricity_capacity_installed, \
           buildings_building_scale_heating_capacities, \
           buildings_building_scale_cooling_capacities