def gen_cities_with_pareto_solutions(city, dict_par_sol, list_sol_nb):
    """
    Generate city objects with energy systems based on indivduals in
    of final pareto frontier

    Parameters
    ----------
    city : object
        City object without energy system
    dict_par_sol : dict
        Dict holding individuals of GA run with solution number as key
        and individual object as value
    list_sol_nb : list (of ints)
        List holding all solution numbers, which should be returned as cities

    Returns
    -------
    dict_cities : dict
        Dict holding solution numbers as key and city object as value
    """

    assert len(list_sol_nb) > 0

    dict_cities = {}

    #  Copy city to prevent unwanted modification by add_bes_to_city
    city = copy.deepcopy(city)

    #  Get list of building ids
    list_build_ids = city.get_list_build_entity_node_ids()

    #  Add all subsystems, necessary to work with GA parser
    addbes.add_bes_to_city(city=city, add_init_boi=False)

    for n in list_sol_nb:
        #  Extract individual
        ind = dict_par_sol[n]

        #  Parse ind to city
        city_new = parseind2city.parse_ind_dict_to_city(dict_ind=ind,
                                                        city=city,
                                                        use_street=False,
                                                        copy_city=True)

        #  Erase all energy system objects, if esys is False
        for id in list_build_ids:
            build = city_new.nodes[id]['entity']
            if build.hasBes:
                if build.bes.hasBattery is False:
                    build.bes.battery = []
                if build.bes.hasBoiler is False:
                    build.bes.boiler = []
                if build.bes.hasChp is False:
                    build.bes.chp = []
                if build.bes.hasElectricalHeater is False:
                    build.bes.electricalHeater = []
                if build.bes.hasHeatpump is False:
                    build.bes.heatpump = []
                if build.bes.hasPv is False:
                    build.bes.pv = []
                if build.bes.hasTes is False:
                    build.bes.tes = []

        #  Add to dict_cities
        dict_cities[n] = city_new

    return dict_cities
def main():
    #  Define pathes
    #  ####################################################################
    this_path = os.path.dirname(os.path.abspath(__file__))
    src_path = os.path.dirname(os.path.dirname(os.path.dirname(this_path)))
    workspace = os.path.join(src_path, 'workspace')

    #  Define path to results folder (holding pickled population files)
    name_res_folder = 'ga_run_dyn_co2_ref_2'
    path_results_folder = os.path.join(workspace, 'output', 'ga_opt',
                                       name_res_folder)

    plot_configs = True
    # plot_configs : bool, optional
    #     Defines, if configurations should be plotted (default: False)

    plot_pareto = True
    #  Defines, if pareto frontier with solution numbers should be plotted

    #  Select individuum number of final population (to be evaluated)
    ind_nb = 1
    #  Select individual by index (ind_nb - 1)

    #  Number of desired individuums
    nb_runs = 100
    failure_tolerance = 1

    do_sampling = True  # Perform initial sampling/load existing sample dicts
    #  If False, use existing sample data on mc_runner object
    sampling_method = 'lhc'

    dem_unc = True
    # dem_unc : bool, optional
    # 	Defines, if thermal, el. and dhw demand are assumed to be uncertain
    # 	(default: True). If True, samples demands. If False, uses reference
    # 	demands.

    heating_off = True
    #  Defines, if heating can be switched of during summer

    #  Suppress print and warnings statements during MC-run
    prevent_printing = False

    #  #############################################

    eeg_pv_limit = True  # Only relevant if evaluate_pop = True

    use_kwkg_lhn_sub = False  # Use KWKG subsidies for LHN

    calc_th_el_cov = True  # Calculate thermal and electric coverage factors

    el_mix_for_chp = False  # Use el. mix for CHP fed-in electricity
    el_mix_for_pv = False  # Use el. mix for PV fed-in electricity

    #  Defines, if pre-generated sample file should be loaded
    #  ##############################

    load_city_n_build_samples = True
    #  Defines, if city and building sample dictionaries should be loaded
    #  instead of generating new samples

    #  kronen_6_resc_2_dict_city_samples are also valid for kronen_6 without
    #  rescaling!
    city_sample_name = 'kronen_6_resc_2_dict_city_samples.pkl'
    build_sample_name = 'kronen_6_resc_2_dict_build_samples.pkl'

    path_city_sample_dict = os.path.join(workspace, 'mc_sample_dicts',
                                         city_sample_name)

    path_build_sample_dict = os.path.join(workspace, 'mc_sample_dicts',
                                          build_sample_name)

    #  Defines, if space heating samples should be loaded (only relevant, if
    #  space heating results of monte-carlo simulation exist and
    #  load_city_n_build_samples is False (as path_build_sample_dict  already
    #  include space heating samples)
    load_sh_mc_res = True

    #  Path to FOLDER with mc sh results (searches for corresponding building ids)
    path_mc_res_folder = os.path.join(workspace, 'mc_sh_results')

    #  Generate el. and dhw profile pool to sample from (time consuming)
    use_profile_pool = True
    #  Only relevant, if sampling_method == 'lhc'
    random_profile = False
    #  Defines, if random samples should be used from profiles. If False,
    #  loops over given profiles (if enough profiles exist).

    gen_use_prof_method = 1
    #  Options:
    #  0: Generate new profiles during runtime
    #  1: Load pre-generated profile sample dictionary

    #  kronen_6_resc_2_dict_profile_20_samples are also valid for kronen_6 without
    #  rescaling!
    el_profile_dict = 'kronen_6_resc_2_dict_profile_20_samples.pkl'
    path_profile_dict = os.path.join(workspace, 'mc_el_profile_pool',
                                     el_profile_dict)

    #  #############################################

    #  Special options
    #  ################
    resc_boilers = False
    #  If resc_boilers is True, rescale boiler sizes with resc_factor
    resc_factor = 1

    #  Name city object
    #  ############################################
    city_name = 'aachen_kronenberg_6.pkl'

    #  Pathes
    #  ################################################################
    path_city = os.path.join(
        workspace,
        'city_objects',
        # 'with_esys',
        'no_esys',
        city_name)

    outfolder = city_name[:-4] + '_reeval_ind_' + str(ind_nb)
    # outfolder = city_name[:-4] + '_ref_boi_2_resc'
    if resc_boilers:
        outfolder = city_name[:-4] + '_reeval_ind_' + str(ind_nb) + '_resc'

    path_city_out = os.path.join(workspace, 'output', 'reevaluate',
                                 str(city_name[:-4]))
    path_out = os.path.join(path_city_out, outfolder)

    if not os.path.exists(path_out):
        os.makedirs(path_out)

    #  Path to save results dict
    res_name = 'mc_run_results_dict.pkl'
    path_res = os.path.join(path_out, res_name)

    #  Path to sampling dict const
    sample_name_const = 'mc_run_sample_dict_const.pkl'
    path_sample_const = os.path.join(path_out, sample_name_const)

    #  Path to sampling dict esys
    sample_name_esys = 'mc_run_sample_dict_esys.pkl'
    path_sample_esys = os.path.join(path_out, sample_name_esys)

    #  Path to save mc settings to
    setup_name = 'mc_run_setup_dict.pkl'
    path_setup = os.path.join(path_out, setup_name)

    profiles_name = 'mc_run_profile_pool_dict.pkl'
    path_profiles = os.path.join(path_out, profiles_name)

    cov_dict_name = 'mc_cov_dict.pkl'
    path_mc_cov = os.path.join(path_out, cov_dict_name)

    #  Path to save figures to. Only relevant, if plot_configs is True
    path_save_fig = os.path.join(path_out, 'figure')

    path_log_file = os.path.join(path_out, 'log_failed_runs.txt')

    file_par_front = str(city_name[:-4]) + '_pareto_front.pkl'
    path_par_front = os.path.join(path_city_out, file_par_front)

    city_out_name = 'city_with_esys_ind_' + str(ind_nb) + '.pkl'
    if resc_boilers:
        city_out_name = 'city_with_esys_ind_ref_boi_2_resc.pkl'
    path_city_obj_out = os.path.join(path_out, city_out_name)

    #  ####################################################################

    #  Load city object instance
    city = pickle.load(open(path_city, mode='rb'))

    #  Workaround: Add additional emissions data, if necessary
    try:
        print(city.environment.co2emissions.co2_factor_pv_fed_in)
    except:
        msg = 'co2em object does not have attribute co2_factor_pv_fed_in. ' \
              'Going to manually add it.'
        warnings.warn(msg)
        city.environment.co2emissions.co2_factor_pv_fed_in = 0.651

    #  ####################################################################

    #  Add bes to all buildings, which do not have bes, yet
    #  Moreover, add initial boiler systems to overwrite existing esys combis
    addbes.add_bes_to_city(city=city, add_init_boi=True)

    #  TODO: Erase, as part has no effect
    # #  Initialize mc runner object and hand over initial city object
    # mc_run = runmc.init_base_mc_objects(city=city)
    #
    # #  Perform initial sampling
    # if sampling_method == 'random':
    #     mc_run.perform_sampling(nb_runs=nb_runs, save_samples=True,
    #                             dem_unc=dem_unc)
    #     #  Save results toself._dict_samples_const = dict_samples_const
    #     #         self._dict_samples_esys = dict_samples_esys
    #
    # elif sampling_method == 'lhc':
    #     mc_run.perform_lhc_sampling(nb_runs=nb_runs, save_res=True,
    #                                 load_sh_mc_res=load_sh_mc_res,
    #                                 path_mc_res_folder=path_mc_res_folder,
    #                                 use_profile_pool=use_profile_pool,
    #                                 gen_use_prof_method=gen_use_prof_method,
    #                                 path_profile_dict=path_profile_dict,
    #                                 load_city_n_build_samples=
    #                                 load_city_n_build_samples,
    #                                 path_city_sample_dict=path_city_sample_dict,
    #                                 path_build_sample_dict=path_build_sample_dict,
    #                                 dem_unc=dem_unc
    #                                 )

    #  Get pickled population result files
    #  ##################################################################
    #  Load results (all pickled population objects into dict)
    dict_gen = andev.load_res(dir=path_results_folder)

    # #  Extract final population
    # (final_pop, list_ann, list_co2) = andev.get_final_pop(dict_gen=dict_gen)
    #
    # #  Extract list of pareto optimal results
    # list_inds_pareto = andev.get_par_front_list_of_final_pop(final_pop)

    try:
        dict_pareto_sol = pickle.load(open(path_par_front, mode='rb'))
    except:
        msg = 'Could not load file from ' + str(path_par_front)
        warnings.warn(msg)
        #  Extract list of pareto optimal results
        list_inds_pareto = andev.get_pareto_front(
            dict_gen=dict_gen,
            size_used=None,  # Nb. Gen.
            nb_ind_used=400)  # Nb. ind.
        #  Parse list of pareto solutions to dict (nb. as keys to re-identify
        #  each solution
        dict_pareto_sol = {}
        for i in range(len(list_inds_pareto)):
            dict_pareto_sol[int(i + 1)] = list_inds_pareto[i]

        #  Save pareto-frontier solution
        pickle.dump(dict_pareto_sol, open(path_par_front, mode='wb'))

    #  Extract list of pareto solutions
    list_inds_pareto = []
    for key in dict_pareto_sol.keys():
        list_inds_pareto.append(dict_pareto_sol[key])

    if plot_pareto:
        #  Print pareto front and energy system configurations
        andev.get_esys_pareto_info(list_pareto_sol=list_inds_pareto)

    #  Extract selected individuum with ind_nb info
    ind_sel = list_inds_pareto[ind_nb - 1]

    # #  ###################################
    # #  Erase pv to generate ref. scenario
    # for id in ind_sel.keys():
    #     if id != 'lhn':
    #         for esys in ind_sel[id].keys():
    #             if esys == 'pv':
    #                 ind_sel[id][esys] = 0
    #
    # for id in ind_sel.keys():
    #     if id != 'lhn':
    #         curr_build = city.nodes[id]['entity']
    #
    #         q_dot_th_max = \
    #             dimfunc.get_max_power_of_building(building=curr_build,
    #                                               get_therm=True,
    #                                               with_dhw=True)
    #
    #         ind_sel[id]['boi'] = 2 * q_dot_th_max
    # #  ###################################

    #  ############################################
    #  Rescale boilers
    if resc_boilers:

        print('Rescale boiler sizes.')
        print('resc_factor boiler: ')
        print(resc_factor)

        for id in ind_sel.keys():
            if id != 'lhn':
                for esys in ind_sel[id].keys():
                    if esys == 'boi':
                        print('Boiler size of building ' + str(id) + ' in kW:')
                        print(ind_sel[id][esys])
                        ind_sel[id][esys] *= resc_factor
                        print('New size (rescaled):')
                        print(ind_sel[id][esys])
                        print()
    #  ############################################

    print('#################################################################')
    print('Selected individual by user: '******'#################################################################')
    print()

    #  Use parser
    #  Generate city with ind object
    city_esys = parseindcit.parse_ind_dict_to_city(dict_ind=ind_sel, city=city)

    if nb_runs == 1:  #  Return single objective values
        (total_annuity, co2) = \
            reevaluate_ind(city_esys=city_esys,
                           nb_runs=nb_runs,
                           sampling_method=sampling_method,
                           do_sampling=do_sampling,
                           failure_tolerance=failure_tolerance,
                           prevent_printing=prevent_printing,
                           heating_off=heating_off,
                           load_sh_mc_res=load_sh_mc_res,
                           path_mc_res_folder=path_mc_res_folder,
                           use_profile_pool=use_profile_pool,
                           gen_use_prof_method=gen_use_prof_method,
                           path_profile_dict=path_profile_dict,
                           random_profile=random_profile,
                           load_city_n_build_samples=load_city_n_build_samples,
                           path_city_sample_dict=path_city_sample_dict,
                           path_build_sample_dict=path_build_sample_dict,
                           eeg_pv_limit=eeg_pv_limit,
                           use_kwkg_lhn_sub=use_kwkg_lhn_sub,
                           calc_th_el_cov=calc_th_el_cov,
                           dem_unc=dem_unc,
                           el_mix_for_chp=el_mix_for_chp,
                           el_mix_for_pv=el_mix_for_pv
                           )
        print('Annuity in Euro/a: ', total_annuity)
        print('Emissions in kg/a: ', co2)
        print()

    else:  # Perform Monte-Carlo economic and ecologic uncertainty analysis
        #  Run reevaluation
        (dict_samples_const, dict_samples_esys, dict_res, dict_mc_setup,
         dict_profiles_lhc, dict_mc_cov) = \
            reevaluate_ind(city_esys=city_esys,
                           nb_runs=nb_runs,
                           sampling_method=sampling_method,
                           do_sampling=do_sampling,
                           failure_tolerance=failure_tolerance,
                           prevent_printing=prevent_printing,
                           heating_off=heating_off,
                           load_sh_mc_res=load_sh_mc_res,
                           path_mc_res_folder=path_mc_res_folder,
                           use_profile_pool=use_profile_pool,
                           gen_use_prof_method=gen_use_prof_method,
                           path_profile_dict=path_profile_dict,
                           random_profile=random_profile,
                           load_city_n_build_samples=load_city_n_build_samples,
                           path_city_sample_dict=path_city_sample_dict,
                           path_build_sample_dict=path_build_sample_dict,
                           eeg_pv_limit=eeg_pv_limit,
                           use_kwkg_lhn_sub=use_kwkg_lhn_sub,
                           calc_th_el_cov=calc_th_el_cov,
                           dem_unc=dem_unc,
                           el_mix_for_chp=el_mix_for_chp,
                           el_mix_for_pv=el_mix_for_pv
                           )

        #  ###################################################################
        pickle.dump(dict_res, open(path_res, mode='wb'))
        print('Saved results dict to: ', path_res)
        print()

        pickle.dump(dict_samples_const, open(path_sample_const, mode='wb'))
        print('Saved sample dict to: ', path_sample_const)
        print()

        pickle.dump(dict_samples_esys, open(path_sample_esys, mode='wb'))
        print('Saved sample dict to: ', path_sample_esys)
        print()

        pickle.dump(dict_mc_setup, open(path_setup, mode='wb'))
        print('Saved mc settings dict to: ', path_setup)
        print()

        if dict_profiles_lhc is not None:
            pickle.dump(dict_profiles_lhc, open(path_profiles, mode='wb'))
            print('Saved profiles dict to: ', path_profiles)
            print()

        if calc_th_el_cov and dict_mc_cov is not None:
            pickle.dump(dict_mc_cov, open(path_mc_cov, mode='wb'))
            print('Saved dict_mc_cov to: ', path_mc_cov)
            print()

        nb_failed_runs = len(dict_mc_setup['idx_failed_runs'])
        print('Nb. failed runs: ', str(nb_failed_runs))
        print()

        list_idx_failed = dict_mc_setup['idx_failed_runs']
        print('Indexes of failed runs: ', str(list_idx_failed))
        print()

        with open(path_log_file, mode='w') as logfile:
            logfile.write('Nb. failed runs: ' + str(nb_failed_runs))
            logfile.write('\nIndexes of failed runs: ' + str(list_idx_failed))

            print('Nb. failed runs: ' + str(nb_failed_runs))
            print('Indexes of failed runs: ' + str(list_idx_failed))

    #  Save city object with esys config
    pickle.dump(city_esys, open(path_city_obj_out, mode='wb'))

    if plot_configs:
        #  Generate figure path
        if not os.path.isdir(path_save_fig):
            os.makedirs(path_save_fig)

        #  Plot and save energy system configuration
        #  You might need to manually adjust input settings, depending
        #  on your city object (such as plot_str_dist or offset)
        citvis.plot_city_district(city=city_esys,
                                  plot_lhn=True,
                                  plot_deg=True,
                                  plot_esys=True,
                                  font_size=11,
                                  save_plot=True,
                                  save_path=path_save_fig,
                                  plot_str_dist=60,
                                  offset=10)
Exemple #3
0
dict_heatloads = estdhl.calc_heat_load_per_building(
    city=city, build_standard=build_standard)

for key in dict_heatloads.keys():
    print('Building id: ', key)
    print('Design heat load (space heating AND hot water) in kW: ',
          round(dict_heatloads[key]) / 1000)
print()

#  #######################################################################
#  Add bes to all buildings, which do not have bes, yet
#  BES are necessary to run GA (enable/disable esys by setting them to True/
#  False on BES, even if object is constantly existent.
#  Boilers can be added, if city has no energy system, boilers are added to
#  prevent EnergySupplyException
addbes.add_bes_to_city(city=city, add_init_boi=add_init_boi)

del_existing_networks = True  # Delete existing LHN/DEGs
#  Necessary to prevent "blocking" of new LHNs by existing LHNs on city object
if del_existing_networks:
    #  Delete all existing energy networks (if some exist)
    delnet.del_energy_network_in_city(city=city)

# Initialize mc runner object and hand over initial city object
mc_run = runmc.init_base_mc_objects(city=city)

#  Perform initial sampling
if sampling_method == 'random':
    mc_run.perform_sampling(nb_runs=nb_runs,
                            save_samples=True,
                            dem_unc=dem_unc)
def reeval_par_sol(path_city,
                   path_save_par,
                   path_results,
                   size_used,
                   nb_ind_used,
                   sampling_method,
                   nb_runs,
                   dem_unc,
                   load_sh_mc_res,
                   path_mc_res_folder,
                   use_profile_pool,
                   gen_use_prof_method,
                   path_profile_dict,
                   load_city_n_build_samples,
                   path_city_sample_dict,
                   path_build_sample_dict,
                   eeg_pv_limit,
                   use_kwkg_lhn_sub,
                   el_mix_for_chp,
                   el_mix_for_pv,
                   heating_off,
                   red_size,
                   failure_tolerance,
                   path_save_dict=None,
                   plot_res=False,
                   save_res=False):
    """
    Reevaluate pareto solutions by reruning economic monte carlo analysis.
    Necessary, if more than default/saved results of opt_ga.py should be
    used/extracted.

    Parameters
    ----------
    path_city : str
    path_save_par
    path_results
    size_used
    nb_ind_used
    sampling_method
    nb_runs
    dem_unc
    load_sh_mc_res
    path_mc_res_folder
    use_profile_pool
    gen_use_prof_method
    path_profile_dict
    load_city_n_build_samples
    path_city_sample_dict
    path_build_sample_dict
    eeg_pv_limit
    use_kwkg_lhn_sub
    el_mix_for_chp
    el_mix_for_pv
    heating_off
    red_size
    failure_tolerance
    path_save_dict : str, optional
    plot_res=False : bool, optional
    save_res : bool, optional

    Returns
    -------
    dict_res
    """

    #  Load city object and add pv_fed_in factor, if not existent
    #  ####################################################################

    #  Load city object instance
    city = pickle.load(open(path_city, mode='rb'))

    #  Workaround: Add additional emissions data, if necessary
    try:
        print(city.environment.co2emissions.co2_factor_pv_fed_in)
    except:
        msg = 'co2em object does not have attribute co2_factor_pv_fed_in. ' \
              'Going to manually add it.'
        warnings.warn(msg)
        city.environment.co2emissions.co2_factor_pv_fed_in = 0.651

    #  ####################################################################

    #  Add bes to all buildings, which do not have bes, yet
    #  Moreover, add initial boiler systems to overwrite existing esys combis
    addbes.add_bes_to_city(city=city, add_init_boi=True)

    #  Extract pareto results
    #  ####################################################################

    try:
        #  Try to load pickled pareto frontier result, if existent
        dict_pareto_sol = pickle.load(open(path_save_par, mode='rb'))
    except:
        print('Could not load pickled dictionary with pareto-frontier '
              'results  from' + str(path_save_par) +
              '. Thus, going to extract pareto solutions from' +
              str(path_results))

        #  Load results dicts from path
        dict_gen = andev.load_res(dir=path_results)

        #  Extract list of pareto-optimal results from overall populations
        list_inds_pareto = \
            andev.get_pareto_front(dict_gen=dict_gen,
                                   size_used=size_used,  # Nb. Gen.
                                   nb_ind_used=nb_ind_used)  # Nb. ind.

        #  Parse list of pareto solutions to dict (nb. as keys to re-identify
        #  each solution
        dict_pareto_sol = {}
        for i in range(len(list_inds_pareto)):
            dict_pareto_sol[int(i + 1)] = list_inds_pareto[i]

        #  Save pareto dict to path
        pickle.dump(dict_pareto_sol, open(path_save_par, mode='wb'))

    #  #####################################################################

    #  Generate mc_runner object

    annuity_obj = annu.EconomicCalculation()
    energy_balance = citeb.CityEBCalculator(city=city)
    city_eco_calc = citecon.CityAnnuityCalc(annuity_obj=annuity_obj,
                                            energy_balance=energy_balance)

    #  Hand over initial city object to mc_runner
    mc_run = mcrun.McRunner(city_eco_calc=city_eco_calc)

    #  Perform initial sampling
    if sampling_method == 'random':
        mc_run.perform_sampling(nb_runs=nb_runs,
                                save_samples=True,
                                dem_unc=dem_unc)
        #  Save results toself._dict_samples_const = dict_samples_const
        #         self._dict_samples_esys = dict_samples_esys
    elif sampling_method == 'lhc':
        mc_run.perform_lhc_sampling(
            nb_runs=nb_runs,
            load_sh_mc_res=load_sh_mc_res,
            path_mc_res_folder=path_mc_res_folder,
            use_profile_pool=use_profile_pool,
            gen_use_prof_method=gen_use_prof_method,
            path_profile_dict=path_profile_dict,
            save_res=True,
            load_city_n_build_samples=load_city_n_build_samples,
            path_city_sample_dict=path_city_sample_dict,
            path_build_sample_dict=path_build_sample_dict,
            dem_unc=dem_unc)

    #  Generate reference system (boilers 4x rescaled) and perform ref. run
    #  ###################################################################

    #  Copy city, only use boilers
    city_copy = copy.deepcopy(city)

    #  Add to copy of mc_runner --> Perform mc run
    addbes.gen_boiler_ref_scenario(city=city_copy)

    #  Copy mc_runner obj. of ga_runner
    mc_run_ref = copy.deepcopy(mc_run)

    #  Replace city object with city_copy
    mc_run_ref._city_eco_calc.energy_balance.city = city_copy

    #  Run MC analysis
    (dict_mc_res_ref, dict_mc_setup_ref, dict_mc_cov_ref) = \
        mc_run_ref.perform_mc_runs(nb_runs=nb_runs,
                                   sampling_method=sampling_method,
                                   eeg_pv_limit=eeg_pv_limit,
                                   use_kwkg_lhn_sub=use_kwkg_lhn_sub,
                                   el_mix_for_chp=el_mix_for_chp,
                                   el_mix_for_pv=el_mix_for_pv,
                                   heating_off=heating_off
                                   )

    if len(dict_mc_setup_ref['idx_failed_runs']) > 0:
        msg = 'Reference run (rescaled boilers) failed!'
        raise AssertionError(msg)

    #  ####################################################################

    print('Start reevaluation of pareto results')
    print('#################################################################')
    print()

    list_keys = list(dict_pareto_sol.keys())
    list_keys.sort()

    #  Dummy result dict
    dict_res = {}

    if red_size is not None:
        list_allowed = list(range(1, nb_ind_used, red_size))
        print('List allowed solution numbers: ', list_allowed)
    else:
        list_allowed = list_keys

    #  Loop over results
    for i in list_keys:
        if i in list_allowed:
            print('Solution key: ', i)

            ind_sel = dict_pareto_sol[i]

            #  Copy mc_runner
            mc_run_copy = copy.deepcopy(mc_run)

            #  Use parser
            #  Generate city with ind object (copy of city)
            parseindcit. \
                parse_ind_dict_to_city(dict_ind=ind_sel,
                                       city=mc_run_copy._city_eco_calc.energy_balance.city,
                                       copy_city=False)

            # #  Add city_eco_calc
            # mc_run_copy._city_eco_calc = city_eco_calc

            #  Reinitialize mc_runner
            mc_run_copy._city_eco_calc.energy_balance.reinit()

            #  Perform MC analysis
            (dict_mc_res, dict_mc_setup, dict_mc_cov) = \
                mc_run_copy.perform_mc_runs(nb_runs=nb_runs,
                                            sampling_method=sampling_method,
                                            eeg_pv_limit=eeg_pv_limit,
                                            failure_tolerance=
                                            failure_tolerance,
                                            use_kwkg_lhn_sub=use_kwkg_lhn_sub,
                                            el_mix_for_chp=el_mix_for_chp,
                                            el_mix_for_pv=el_mix_for_pv,
                                            heating_off=heating_off
                                            )

            #  Initialize mc analyze object
            mc_analyze = analyzemc.EcoMCRunAnalyze()

            #  Hand over results and setup dict
            mc_analyze.dict_results = dict_mc_res
            mc_analyze.dict_setup = dict_mc_setup

            #  Extract basic results
            mc_analyze.extract_basic_results()
            mc_analyze.calc_annuity_to_net_energy_ratio()
            mc_analyze.calc_co2_to_net_energy_ratio()
            mc_analyze.calc_dimless_cost_co2(dict_ref_run=dict_mc_res_ref)

            #  Perform flexibility calculation
            city_flex_copy = copy.deepcopy(
                mc_run_copy._city_eco_calc.energy_balance.city)

            (beta_el_pos, beta_el_neg) = \
                flexquant.calc_beta_el_city(city=city_flex_copy)

            #  Save results
            dict_res_ind = {}

            dict_res_ind['array_dimless_cost'] = mc_analyze._array_dimless_cost
            dict_res_ind['array_dimless_co2'] = mc_analyze._array_dimless_co2
            dict_res_ind['array_ann'] = mc_analyze._array_ann_mod
            dict_res_ind['array_co2'] = mc_analyze._array_co2_mod

            dict_res_ind['array_sh'] = mc_analyze._array_sh_dem_mod
            dict_res_ind['array_el'] = mc_analyze._array_el_dem_mod
            dict_res_ind['array_dhw'] = mc_analyze._array_dhw_dem_mod

            # dict_res_ind['beta_el_pos'] = beta_el_pos
            # dict_res_ind['beta_el_neg'] = beta_el_neg

            dict_res_ind[
                'list_idx_failed_runs'] = mc_analyze._list_idx_failed_runs

            #  Save to overall results dict
            dict_res[i] = dict_res_ind

    if save_res:
        #  Save dict_res
        pickle.dump(dict_res, open(path_save_dict, mode='wb'))

    if plot_res:
        #  Plot mean dimless function values
        fig = plt.figure()

        for i in list_keys:
            if i in list_allowed:
                print('Solution key: ', i)

                dimless_cost_mean = np.mean(dict_res[i]['array_dimless_cost'])
                dimless_co2_mean = np.mean(dict_res[i]['array_dimless_co2'])

                print(dimless_cost_mean)
                print(dimless_co2_mean)

                plt.plot(
                    [dimless_cost_mean],
                    [dimless_co2_mean],
                    marker='o',
                    linestyle='',
                    markersize=3,
                )

        plt.xlabel('Dimensionless cost')
        plt.ylabel('Dimensionless emissions')
        plt.show()
        plt.close()

    return dict_res
    def test_parse_ind_dict_to_city2(self):
        #  Generate city object
        #  Create extended environment of pycity_calc
        year = 2010
        timestep = 900  # Timestep in seconds
        location = (51.529086, 6.944689)  # (latitude, longitute) of Bottrop
        altitude = 55  # Altitude of Bottrop

        #  Generate timer object
        timer = time.TimerExtended(timestep=timestep, year=year)

        #  Generate weather object
        weather = Weather.Weather(timer,
                                  useTRY=True,
                                  location=location,
                                  altitude=altitude)

        #  Generate market object
        market = germarkt.GermanMarket()

        #  Generate co2 emissions object
        co2em = co2.Emissions(year=year)

        #  Generate environment
        environment = env.EnvironmentExtended(timer,
                                              weather,
                                              prices=market,
                                              location=location,
                                              co2em=co2em)

        #  Generate city object
        city_object = city.City(environment=environment)

        for i in range(7):
            extended_building = build_ex.BuildingExtended(
                environment,
                build_year=1990,
                mod_year=2003,
                build_type=0,
                roof_usabl_pv_area=30,
                net_floor_area=150,
                height_of_floors=3,
                nb_of_floors=2,
                neighbour_buildings=0,
                residential_layout=0,
                attic=0,
                cellar=1,
                construction_type='heavy',
                dormer=0)

            #  Create demands (with standardized load profiles (method=1))
            heat_demand = SpaceHeating.SpaceHeating(environment,
                                                    method=1,
                                                    profile_type='HEF',
                                                    livingArea=300,
                                                    specificDemand=100)

            el_demand = ElectricalDemand.ElectricalDemand(environment,
                                                          method=1,
                                                          annualDemand=3000,
                                                          profileType="H0")

            #  Create apartment
            apartment = Apartment.Apartment(environment)

            #  Add demands to apartment
            apartment.addMultipleEntities([heat_demand, el_demand])

            #  Add apartment to extended building
            extended_building.addEntity(entity=apartment)

            #  Add buildings to city_object
            city_object.add_extended_building(extended_building,
                                              position=point.Point(0, i * 10))

        addbes.add_bes_to_city(city=city_object)

        chp_size = 10000
        boi_size = 30000
        tes_size = 500
        pv_area = 30

        dict_b1 = {
            'chp': chp_size,
            'boi': boi_size,
            'tes': tes_size,
            'eh': 0,
            'hp_aw': 0,
            'hp_ww': 0,
            'pv': pv_area,
            'bat': 0
        }

        dict_b2 = {
            'chp': chp_size,
            'boi': boi_size,
            'tes': tes_size,
            'eh': 0,
            'hp_aw': 0,
            'hp_ww': 0,
            'pv': pv_area,
            'bat': 0
        }

        dict_no = {
            'chp': 0,
            'boi': 0,
            'tes': 0,
            'eh': 0,
            'hp_aw': 0,
            'hp_ww': 0,
            'pv': 0,
            'bat': 0
        }

        ind = {
            1001: dict_b1,
            1002: dict_no,
            1003: dict_b2,
            1004: copy.copy(dict_no),
            1005: copy.copy(dict_no),
            1006: copy.copy(dict_no),
            1007: copy.copy(dict_no),
            'lhn': [[1001, 1002], [1003, 1004, 1005, 1006, 1007]]
        }

        city_obj = parse_ind_to_city.parse_ind_dict_to_city(dict_ind=ind,
                                                            city=city_object)

        assert city_obj.nodes[1001]['entity'].bes.chp.qNominal == chp_size
        assert city_obj.nodes[1001]['entity'].bes.boiler.qNominal == boi_size
        assert city_obj.nodes[1001]['entity'].bes.tes.capacity == tes_size

        assert city_obj.nodes[1003]['entity'].bes.chp.qNominal == chp_size
        assert city_obj.nodes[1003]['entity'].bes.boiler.qNominal == boi_size
        assert city_obj.nodes[1003]['entity'].bes.tes.capacity == tes_size

        assert city_obj.edges[1001, 1002]['network_type'] == 'heating'
        assert city_obj.edges[1003, 1004]['network_type'] == 'heating'
        assert city_obj.edges[1004, 1005]['network_type'] == 'heating'
        assert city_obj.edges[1005, 1006]['network_type'] == 'heating'
        assert city_obj.edges[1006, 1007]['network_type'] == 'heating'

        checkeb.check_eb_requirements(city=city_obj)