Ejemplo n.º 1
0
def evolutionary_algo_main(locator,
                           building_names,
                           extra_costs,
                           extra_CO2,
                           extra_primary_energy,
                           solar_features,
                           network_features,
                           gv,
                           genCP=0):
    """
    Evolutionary algorithm to optimize the district energy system's design.
    This algorithm optimizes the size and operation of technologies for a district heating network.
    electrical network are not considered but their burdens in terms electricity costs, efficiency and emissions
    is added on top of the optimization.
    The equipment for cooling networks is not optimized as it is assumed that all customers with cooling needs will be
    connected to a lake. in case there is not enough capacity from the lake, a chiller and cooling tower is used to
    cover the extra needs.

    :param locator: locator class
    :param building_names: vector with building names
    :param extra_costs: costs calculated before optimization of specific energy services
     (process heat and electricity)
    :param extra_CO2: green house gas emissions calculated before optimization of specific energy services
     (process heat and electricity)
    :param extra_primary_energy: primary energy calculated before optimization of specific energy services
     (process heat and electricity)
    :param solar_features: object class with vectors and values of interest for the integration of solar potentials
    :param network_features: object class with linear coefficients of the network obtained after its optimization
    :param gv: global variables class
    :param genCP: 0
    :type locator: class
    :type building_names: array
    :type extra_costs: float
    :type extra_CO2: float
    :type extra_primary_energy: float
    :type solar_features: class
    :type network_features: class
    :type gv: class
    :type genCP: int
    :return: for every generation 'g': it stores the results of every generation of the genetic algorithm in the
     subfolders locator.get_optimization_master_results_folder() as a python pickle file.
    :rtype: pickled file
    """
    t0 = time.clock()

    # get number of buildings
    nBuildings = len(building_names)

    # DEFINE OBJECTIVE FUNCTION
    def objective_function(ind):
        (costs, CO2, prim) = evaluation.evaluation_main(
            ind, building_names, locator, extra_costs, extra_CO2,
            extra_primary_energy, solar_features, network_features, gv)
        return (costs, CO2, prim)

    # SET-UP EVOLUTIONARY ALGORITHM
    # Contains 3 minimization objectives : Costs, CO2 emissions, Primary Energy Needs
    creator.create("Fitness", base.Fitness, weights=(-1.0, -1.0, -1.0))
    creator.create("Individual", list, fitness=creator.Fitness)
    toolbox = base.Toolbox()
    toolbox.register("generate", generation.generate_main, nBuildings, gv)
    toolbox.register("individual", tools.initIterate, creator.Individual,
                     toolbox.generate)
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    toolbox.register("evaluate", objective_function)

    ntwList = ["1" * nBuildings]
    epsInd = []
    invalid_ind = []

    # Evolutionary strategy
    if genCP is 0:
        # create population
        pop = toolbox.population(n=gv.initialInd)

        # Check distribution
        for ind in pop:
            evaluation.checkNtw(ind, ntwList, locator, gv)

        # Evaluate the initial population
        print "Evaluate initial population"
        fitnesses = map(toolbox.evaluate, pop)

        for ind, fit in zip(pop, fitnesses):
            ind.fitness.values = fit
            print ind.fitness.values, "fit"

        # Save initial population
        print "Save Initial population \n"

        with open(locator.get_optimization_checkpoint_initial(), "wb") as fp:
            cp = dict(population=pop,
                      generation=0,
                      networkList=ntwList,
                      epsIndicator=[],
                      testedPop=[],
                      population_fitness=fitnesses)
            json.dump(cp, fp)

    else:
        print "Recover from CP " + str(genCP) + "\n"

        with open(locator.get_optimization_checkpoint(genCP), "rb") as CPread:
            CPunpick = Unpickler(CPread)
            cp = CPunpick.load()
            pop = cp["population"]
            ntwList = cp["networkList"]
            epsInd = cp["epsIndicator"]

    PROBA, SIGMAP = gv.PROBA, gv.SIGMAP

    # Evolution starts !
    g = genCP
    stopCrit = False  # Threshold for the Epsilon indicator, Not used

    while g < gv.NGEN and not stopCrit and (time.clock() - t0) < gv.maxTime:

        g += 1
        print "Generation", g

        offspring = list(pop)

        # Apply crossover and mutation on the pop
        print "CrossOver"
        for ind1, ind2 in zip(pop[::2], pop[1::2]):
            child1, child2 = cx.cxUniform(ind1, ind2, PROBA, gv)
            offspring += [child1, child2]

        # First half of the master: create new un-correlated configurations
        if g < gv.NGEN / 2:
            for mutant in pop:
                print "Mutation Flip"
                offspring.append(mut.mutFlip(mutant, PROBA, gv))
                print "Mutation Shuffle"
                offspring.append(mut.mutShuffle(mutant, PROBA, gv))
                print "Mutation GU \n"
                offspring.append(mut.mutGU(mutant, PROBA, gv))

        # Third quarter of the master: keep the good individuals but modify the shares uniformly
        elif g < gv.NGEN * 3 / 4:
            for mutant in pop:
                print "Mutation Uniform"
                offspring.append(mut.mutUniformCap(mutant, gv))

        # Last quarter: keep the very good individuals and modify the shares with Gauss distribution
        else:
            for mutant in pop:
                print "Mutation Gauss"
                offspring.append(mut.mutGaussCap(mutant, SIGMAP, gv))

        # Evaluate the individuals with an invalid fitness
        # NB: every generation leads to the reevaluation of (n/2) / (n/4) / (n/4) individuals
        # (n being the number of individuals in the previous generation)
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]

        print "Update Network list \n"
        for ind in invalid_ind:
            evaluation.checkNtw(ind, ntwList, locator, gv)

        print "Re-evaluate the population"
        fitnesses = map(toolbox.evaluate, invalid_ind)

        print "......................................."
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit
            print ind.fitness.values, "new fit"
        print "....................................... \n"

        # Select the Pareto Optimal individuals
        selection = sel.selectPareto(offspring, gv)

        # Compute the epsilon criteria [and check the stopping criteria]
        epsInd.append(evaluation.epsIndicator(pop, selection))
        #if len(epsInd) >1:
        #    eta = (epsInd[-1] - epsInd[-2]) / epsInd[-2]
        #    if eta < gv.epsMargin:
        #        stopCrit = True

        # The population is entirely replaced by the best individuals
        print "Replace the population \n"
        pop[:] = selection

        print "....................................... \n GENERATION ", g
        for ind in pop:
            print ind.fitness.values, "selected fit"
        print "....................................... \n"

        # Create Checkpoint if necessary
        if g % gv.fCheckPoint == 0:
            print "Create CheckPoint", g, "\n"
            fitnesses = map(toolbox.evaluate, pop)
            with open(locator.get_optimization_checkpoint(g), "wb") as fp:
                cp = dict(population=pop,
                          generation=g,
                          networkList=ntwList,
                          epsIndicator=epsInd,
                          testedPop=invalid_ind,
                          population_fitness=fitnesses)
                json.dump(cp, fp)

    if g == gv.NGEN:
        print "Final Generation reached"
    else:
        print "Stopping criteria reached"

    # Saving the final results
    print "Save final results. " + str(
        len(pop)) + " individuals in final population"
    print "Epsilon indicator", epsInd, "\n"
    fitnesses = map(toolbox.evaluate, pop)
    with open(locator.get_optimization_checkpoint_final(), "wb") as fp:
        cp = dict(population=pop,
                  generation=g,
                  networkList=ntwList,
                  epsIndicator=epsInd,
                  testedPop=invalid_ind,
                  population_fitness=fitnesses)
        json.dump(cp, fp)

    print "Master Work Complete \n"

    return pop, epsInd
Ejemplo n.º 2
0
def non_dominated_sorting_genetic_algorithm(locator, building_names, extra_costs, extra_CO2, extra_primary_energy, solar_features,
                                            network_features, gv, config, prices, lca):

    t0 = time.clock()

    genCP = config.optimization.recoverycheckpoint

    # genCP = 2
    # NDIM = 30
    # MU = 500

    # initiating hall of fame size and the function evaluations
    halloffame_size = config.optimization.halloffame
    function_evals = 0
    euclidean_distance = 0
    spread = 0

    # get number of buildings
    nBuildings = len(building_names)


    # SET-UP EVOLUTIONARY ALGORITHM
    # Contains 3 minimization objectives : Costs, CO2 emissions, Primary Energy Needs
    # this part of the script sets up the optimization algorithm in the same syntax of DEAP toolbox

    toolbox = base.Toolbox()

    toolbox.register("generate", generate_main, nBuildings, config)
    toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.generate)
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    toolbox.register("evaluate", objective_function_wrapper)
    toolbox.register("select", tools.selNSGA2)


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

    # Initialization of variables
    DHN_network_list = ["1"*nBuildings]
    DCN_network_list = ["1"*nBuildings]
    halloffame = []
    halloffame_fitness = []
    epsInd = []


    columns_of_saved_files = ['generation', 'individual', 'CHP/Furnace', 'CHP/Furnace Share', 'Base Boiler', 'Base Boiler Share', 'Peak Boiler', 'Peak Boiler Share',
               'Heating Lake', 'Heating Lake Share', 'Heating Sewage', 'Heating Sewage Share', 'GHP', 'GHP Share',
               'Data Centre', 'Compressed Air', 'PV', 'PV Area Share', 'PVT', 'PVT Area Share', 'SC_ET', 'SC_ET Area Share',
               'SC_FP', 'SC_FP Area Share', 'DHN Temperature', 'DHN unit configuration', 'Lake Cooling', 'Lake Cooling Share', 'VCC Cooling', 'VCC Cooling Share',
               'Absorption Chiller', 'Absorption Chiller Share', 'Storage', 'Storage Share', 'DCN Temperature', 'DCN unit configuration']
    for i in building_names: #DHN
        columns_of_saved_files.append(str(i) + ' DHN')

    for i in building_names: #DCN
        columns_of_saved_files.append(str(i) + ' DCN')

    columns_of_saved_files.append('TAC')
    columns_of_saved_files.append('CO2 emissions')
    columns_of_saved_files.append('Primary Energy')

    stats = tools.Statistics(lambda ind: ind.fitness.values)
    # stats.register("avg", numpy.mean, axis=0)
    # stats.register("std", numpy.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"

    if genCP is 0:

        pop = toolbox.population(n=config.optimization.initialind)

        for ind in pop:
            evaluation.checkNtw(ind, DHN_network_list, DCN_network_list, locator, gv, config, building_names)


        # Evaluate the initial population
        print "Evaluate initial population"
        DHN_network_list = DHN_network_list[
                           1:]  # done this to remove the first individual in the ntwList as it is an initial value
        DCN_network_list = DCN_network_list[1:]

        # 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(genCP, len(invalid_ind)),
                                     repeat(building_names, len(invalid_ind)),
                                     repeat(locator, len(invalid_ind)), repeat(solar_features, len(invalid_ind)),
                                     repeat(network_features, len(invalid_ind)), repeat(gv, len(invalid_ind)),
                                     repeat(config, len(invalid_ind)),
                                     repeat(prices, len(invalid_ind)), repeat(lca, len(invalid_ind))))

        function_evals = function_evals + len(invalid_ind)   # keeping track of number of function evaluations
        # linking every individual with the corresponding fitness, this also keeps a track of the number of function
        # evaluations. This can further be used as a stopping criteria in future
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        pop = toolbox.select(pop, len(pop))  # assigning crowding distance

        # halloffame is the best individuals that are observed in all generations
        # the size of the halloffame is linked to the number of initial individuals
        if len(halloffame) <= halloffame_size:
            halloffame.extend(pop)

        print "Save Initial population \n"

        zero_data = np.zeros(shape = (len(invalid_ind), len(columns_of_saved_files)))
        saved_dataframe_for_each_generation = pd.DataFrame(zero_data, columns = columns_of_saved_files)

        for i, ind in enumerate(invalid_ind):
            saved_dataframe_for_each_generation['individual'][i] = i
            saved_dataframe_for_each_generation['generation'][i] = genCP
            for j in range(len(columns_of_saved_files) - 5):
                saved_dataframe_for_each_generation[columns_of_saved_files[j+2]][i] = ind[j]
            saved_dataframe_for_each_generation['TAC'][i] = ind.fitness.values[0]
            saved_dataframe_for_each_generation['CO2 emissions'][i] = ind.fitness.values[1]
            saved_dataframe_for_each_generation['Primary Energy'][i] = ind.fitness.values[2]

        saved_dataframe_for_each_generation.to_csv(locator.get_optimization_individuals_in_generation(genCP))

        with open(locator.get_optimization_checkpoint_initial(),"wb") as fp:
            cp = dict(nsga_selected_population=pop, generation=0, DHN_List=DHN_network_list, DCN_list = DCN_network_list, tested_population=[],
                      tested_population_fitness=fitnesses, halloffame=halloffame, halloffame_fitness=halloffame_fitness)
            json.dump(cp, fp)

    else:
        print "Recover from CP " + str(genCP) + "\n"
        # import the checkpoint based on the genCP
        with open(locator.get_optimization_checkpoint(genCP), "rb") as fp:
            cp = json.load(fp)
            pop = toolbox.population(n=config.optimization.initialind)
            for i in xrange(len(pop)):
                for j in xrange(len(pop[i])):
                    pop[i][j] = cp['population'][i][j]
            DHN_network_list = DHN_network_list
            DCN_network_list = DCN_network_list
            epsInd = cp["epsIndicator"]


            for ind in pop:
                evaluation.checkNtw(ind, DHN_network_list, DCN_network_list, locator, gv, config, building_names)

            # 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(genCP, len(invalid_ind)),
                                         repeat(building_names, len(invalid_ind)),
                                         repeat(locator, len(invalid_ind)), repeat(solar_features, len(invalid_ind)),
                                         repeat(network_features, len(invalid_ind)), repeat(gv, len(invalid_ind)),
                                         repeat(config, len(invalid_ind)),
                                         repeat(prices, len(invalid_ind)), repeat(lca, len(invalid_ind))))

            function_evals = function_evals + len(invalid_ind)  # keeping track of number of function evaluations
            # linking every individual with the corresponding fitness, this also keeps a track of the number of function
            # evaluations. This can further be used as a stopping criteria in future
            for ind, fit in zip(pop, fitnesses):
                ind.fitness.values = fit

            pop = toolbox.select(pop, len(pop))  # assigning crowding distance

    proba, sigmap = PROBA, SIGMAP

    # variables used for generating graphs
    # graphs are being generated for every generation, it is shown in 2D plot with colorscheme for the 3rd objective
    xs = [((objectives[0])) for objectives in fitnesses]  # Costs
    ys = [((objectives[1])) for objectives in fitnesses]  # GHG emissions
    zs = [((objectives[2])) for objectives in fitnesses]  # MJ

    # normalization is used for optimization metrics as the objectives are all present in different scales
    # to have a consistent value for normalization, the values of the objectives of the initial generation are taken
    normalization = [max(xs) - min(xs), max(ys) - min(ys), max(zs) - min(zs)]

    xs = [a / 10**6 for a in xs]
    ys = [a / 10**6 for a in ys]
    zs = [a / 10**6 for a in zs]

    # Evolution starts !

    g = genCP
    stopCrit = False # Threshold for the Epsilon indicator, Not used

    while g < config.optimization.ngen and not stopCrit and (time.clock() - t0) < config.optimization.maxtime:

        # Initialization of variables
        DHN_network_list = ["1" * nBuildings]

        g += 1
        print "Generation", g
        offspring = list(pop)
        # Apply crossover and mutation on the pop
        for ind1, ind2 in zip(pop[::2], pop[1::2]):
            child1, child2 = crossover.cxUniform(ind1, ind2, proba, nBuildings)
            offspring += [child1, child2]

        for mutant in pop:
            mutant = mutations.mutFlip(mutant, proba, nBuildings)
            mutant = mutations.mutShuffle(mutant, proba, nBuildings)
            offspring.append(mutations.mutGU(mutant, proba))

        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]

        for ind in invalid_ind:
            evaluation.checkNtw(ind, DHN_network_list, DCN_network_list, locator, gv, config, building_names)

        # Evaluate the individuals with an invalid fitness
        fitnesses = toolbox.map(toolbox.evaluate,
                                izip(invalid_ind, range(len(invalid_ind)), repeat(g, len(invalid_ind)),
                                     repeat(building_names, len(invalid_ind)),
                                     repeat(locator, len(invalid_ind)), repeat(solar_features, len(invalid_ind)),
                                     repeat(network_features, len(invalid_ind)), repeat(gv, len(invalid_ind)),
                                     repeat(config, len(invalid_ind)),
                                     repeat(prices, len(invalid_ind)), repeat(lca, len(invalid_ind))))

        function_evals = function_evals + len(invalid_ind)   # keeping track of number of function evaluations
        # linking every individual with the corresponding fitness, this also keeps a track of the number of function
        # evaluations. This can further be used as a stopping criteria in future
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        zero_data = np.zeros(shape = (len(invalid_ind), len(columns_of_saved_files)))
        saved_dataframe_for_each_generation = pd.DataFrame(zero_data, columns = columns_of_saved_files)

        for i, ind in enumerate(invalid_ind):
            saved_dataframe_for_each_generation['individual'][i] = i
            saved_dataframe_for_each_generation['generation'][i] = g
            for j in range(len(columns_of_saved_files) - 5):
                saved_dataframe_for_each_generation[columns_of_saved_files[j+2]][i] = ind[j]
            saved_dataframe_for_each_generation['TAC'][i] = ind.fitness.values[0]
            saved_dataframe_for_each_generation['CO2 emissions'][i] = ind.fitness.values[1]
            saved_dataframe_for_each_generation['Primary Energy'][i] = ind.fitness.values[2]

        saved_dataframe_for_each_generation.to_csv(locator.get_optimization_individuals_in_generation(g))

        selection = toolbox.select(pop + invalid_ind, config.optimization.initialind) # assigning crowding distance

        if len(halloffame) <= halloffame_size:
            halloffame.extend(selection)
        else:
            halloffame.extend(selection)
            halloffame = toolbox.select(halloffame, halloffame_size)

        halloffame_fitness = []
        for ind in halloffame:
            halloffame_fitness.append(ind.fitness.values)

        # Compute the epsilon criteria [and check the stopping criteria]
        epsInd.append(evaluation.epsIndicator(pop, selection))
        # compute the optimization metrics for every front apart from generation 0
        euclidean_distance, spread = convergence_metric(pop, selection, normalization)

        pop[:] = selection


        # Create Checkpoint if necessary
        if g % config.optimization.fcheckpoint == 0:
            print "Create CheckPoint", g, "\n"
            with open(locator.get_optimization_checkpoint(g), "wb") as fp:
                cp = dict(nsga_selected_population=pop, generation=g, DHN_List=DHN_network_list, DCN_list = DCN_network_list,
                          tested_population=invalid_ind, tested_population_fitness=fitnesses, epsIndicator=epsInd,
                          halloffame=halloffame, halloffame_fitness=halloffame_fitness,
                          euclidean_distance=euclidean_distance, spread=spread)
                json.dump(cp, fp)


    if g == config.optimization.ngen:
        print "Final Generation reached"
    else:
        print "Stopping criteria reached"

    # Dataframe with all the individuals whose objective functions are calculated, gathering all the results from
    # multiple generations
    df = pd.read_csv(locator.get_optimization_individuals_in_generation(0))
    for i in range(config.optimization.ngen):
        df = df.append(pd.read_csv(locator.get_optimization_individuals_in_generation(i+1)))
    df.to_csv(locator.get_optimization_all_individuals())
    # Saving the final results
    print "Save final results. " + str(len(pop)) + " individuals in final population"
    with open(locator.get_optimization_checkpoint_final(), "wb") as fp:
        cp = dict(nsga_selected_population=pop, generation=g, DHN_List=DHN_network_list, DCN_list = DCN_network_list,
                  tested_population=invalid_ind, tested_population_fitness=fitnesses, epsIndicator=epsInd,
                  halloffame=halloffame, halloffame_fitness=halloffame_fitness,
                  euclidean_distance=euclidean_distance, spread=spread)
        json.dump(cp, fp)

    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
Ejemplo n.º 3
0
def individual_evaluation(generation, level, size, variable_groups):
    """
    :param generation: Generation of the optimization in which the individual evaluation is to be done
    :type generation: int
    :param level: Number of the uncertain scenario. For each scenario, the objectives are calculated
    :type level: int
    :param size: Total uncertain scenarios developed. See 'uncertainty.csv'
    :type size: int
    :return: Function saves the new objectives in a json file
    """

    from cea.optimization.preprocessing.preprocessing_main import preproccessing
    gv = cea.globalvar.GlobalVariables()
    scenario_path = gv.scenario_reference
    locator = cea.inputlocator.InputLocator(scenario_path)
    config = cea.config.Configuration()
    weather_file = locator.get_default_weather()

    with open(
            locator.get_optimization_master_results_folder() + "\CheckPoint_" +
            str(generation), "rb") as fp:
        data = json.load(fp)

    pop = data['population']
    ntwList = data['networkList']

    # # Uncertainty Part
    row = []
    with open(locator.get_uncertainty_results_folder() +
              '\uncertainty.csv') as f:
        reader = csv.reader(f)
        for i in xrange(size + 1):
            row.append(next(reader))

    j = level + 1

    for i in xrange(len(row[0]) - 1):
        setattr(gv, row[0][i + 1], float(row[j][i + 1]))

    total_demand = pd.read_csv(locator.get_total_demand())
    building_names = total_demand.Name.values
    gv.num_tot_buildings = total_demand.Name.count()
    lca = lca_calculations(locator, config)
    prices = Prices(locator, config)

    extra_costs, extra_CO2, extra_primary_energy, solarFeat = preproccessing(
        locator, total_demand, building_names, weather_file, gv)
    network_features = network_opt.network_opt_main()

    def objective_function(ind, ind_num):
        (costs, CO2, prim) = evaluation.evaluation_main(
            ind, building_names, locator, solarFeat, network_features, gv,
            config, prices, lca, ind_num, generation)
        # print (costs, CO2, prim)
        return (costs, CO2, prim)

    fitness = []
    for i in xrange(gv.initialInd):
        evaluation.checkNtw(pop[i], ntwList, locator, gv)
        fitness.append(objective_function(pop[i], i))

    with open(locator.get_uncertainty_checkpoint(level), "wb") as fp:
        cp = dict(population=pop,
                  uncertainty_level=level,
                  population_fitness=fitness)
        json.dump(cp, fp)