Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
main.py 12.70 KiB
import pickle
import yaml
from os.path import join, isfile
from numpy import array, sum
from pyomo.opt import SolverFactory
import time
import argparse

from helpers import read_inputs, init_folder, custom_log, xarray_to_ndarray, generate_jl_input, get_deployment_vector
from tools import read_database, return_filtered_coordinates, selected_data, return_output, resource_quality_mapping, \
    critical_window_mapping, sites_position_mapping
from models import build_ip_model


def parse_args():

    parser = argparse.ArgumentParser(description='Command line arguments.')

    parser.add_argument('--c', type=int)
    parser.add_argument('--p', type=int, default=None)
    parser.add_argument('--run_BB', type=bool, default=False)
    parser.add_argument('--run_MIR', type=bool, default=False)
    parser.add_argument('--run_MIRSA', type=bool, default=False)
    parser.add_argument('--run_GRED_DET', type=bool, default=False)
    parser.add_argument('--run_GRED_STO', type=bool, default=False)
    parser.add_argument('--run_RAND', type=bool, default=False)
    parser.add_argument('--run_SGHLS', type=bool, default=False)

    parsed_args = vars(parser.parse_args())

    return parsed_args


def single_true(iterable):
    i = iter(iterable)
    return any(i) and not any(i)


if __name__ == '__main__':

    args = parse_args()

    model_parameters = read_inputs('../config_model.yml')
    siting_parameters = model_parameters['siting_params']
    tech_parameters = read_inputs('../config_techs.yml')

    data_path = model_parameters['data_path']
    spatial_resolution = model_parameters['spatial_resolution']
    time_horizon = model_parameters['time_slice']

    deployment_dict = get_deployment_vector(model_parameters['regions'],
                                            model_parameters['technologies'],
                                            model_parameters['deployments'])

    if isfile(join(data_path, 'input/criticality_matrix.p')):

        custom_log(' WARNING! Instance data read from files.')
        criticality_data = pickle.load(open(join(data_path, 'input/criticality_matrix.p'), 'rb'))
        site_coordinates = pickle.load(open(join(data_path, 'input/site_coordinates.p'), 'rb'))
        capacity_factors_data = pickle.load(open(join(data_path, 'input/capacity_factors_data.p'), 'rb'))
        site_positions = pickle.load(open(join(data_path, 'input/site_positions.p'), 'rb'))

        r = list(site_coordinates.keys())
        d = sum(model_parameters['deployments'])
        t = model_parameters['technologies']
        ts = len(capacity_factors_data[list(site_coordinates.keys())[0]][model_parameters['technologies'][0]].time)
        custom_log(f" Reading data for a model with a spatial resolution of {float(spatial_resolution)}, "
                   f"covering {r}, siting {d} {t} sites and {ts} time steps.")

    else:

        custom_log('Files not available. Starting data pre-processing.')

        database = read_database(data_path, spatial_resolution)
        site_coordinates = return_filtered_coordinates(database, model_parameters, tech_parameters)
        truncated_data = selected_data(database, site_coordinates, time_horizon)
        capacity_factors_data = return_output(truncated_data, data_path)
        time_windows_data = resource_quality_mapping(capacity_factors_data, siting_parameters)
        criticality_data = xarray_to_ndarray(critical_window_mapping(time_windows_data, model_parameters))
        site_positions = sites_position_mapping(time_windows_data)

        pickle.dump(criticality_data, open(join(data_path, 'input/criticality_matrix.p'), 'wb'), protocol=4)
        pickle.dump(site_coordinates, open(join(data_path, 'input/site_coordinates.p'), 'wb'), protocol=4)
        pickle.dump(capacity_factors_data, open(join(data_path, 'input/capacity_factors_data.p'), 'wb'), protocol=4)
        pickle.dump(site_positions, open(join(data_path, 'input/site_positions.p'), 'wb'), protocol=4)

        custom_log(' Data read. Building model.')

    siting_parameters['solution_method']['BB']['set'] = args['run_BB']
    siting_parameters['solution_method']['BB']['mir'] = args['run_MIR']
    siting_parameters['solution_method']['MIRSA']['set'] = args['run_MIRSA']
    siting_parameters['solution_method']['GRED_DET']['set'] = args['run_GRED_DET']
    siting_parameters['solution_method']['GRED_STO']['set'] = args['run_GRED_STO']
    siting_parameters['solution_method']['GRED_STO']['p'] = args['p']
    siting_parameters['solution_method']['RAND']['set'] = args['run_RAND']
    siting_parameters['solution_method']['SGHLS']['set'] = args['run_SGHLS']
    siting_parameters['solution_method']['SGHLS']['p'] = args['p']

    c = args['c']

    if not single_true([args['run_BB'], args['run_MIRSA'], args['run_GRED_DET'], args['run_GRED_STO'],
                        args['run_RAND'], args['run_SGHLS']]):
        raise ValueError(' More than one run selected in the argparser.')

    if siting_parameters['solution_method']['BB']['set']:

        custom_log(' BB chosen to solve the IP.')
        params = siting_parameters['solution_method']['BB']

        output_folder = init_folder(model_parameters, c, f"_BB_MIR_{args['run_MIR']}")
        with open(join(output_folder, 'config_model.yaml'), 'w') as outfile:
            yaml.dump(model_parameters, outfile, default_flow_style=False, sort_keys=False)
        with open(join(output_folder, 'config_techs.yaml'), 'w') as outfile:
            yaml.dump(tech_parameters, outfile, default_flow_style=False, sort_keys=False)

        # Solver options for the MIP problem
        opt = SolverFactory(params['solver'])
        opt.options['MIPGap'] = params['mipgap']
        opt.options['Threads'] = params['threads']
        opt.options['TimeLimit'] = params['timelimit']

        instance = build_ip_model(deployment_dict, site_coordinates, criticality_data,
                                  c, output_folder, args['run_MIR'])
        custom_log(' Sending model to solver.')

        results = opt.solve(instance, tee=False, keepfiles=False,
                            report_timing=False, logfile=join(output_folder, 'solver_log.log'))

        objective = instance.objective()
        x_values = array(list(instance.x.extract_values().values()))

        pickle.dump(x_values, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(objective, open(join(output_folder, 'objective_vector.p'), 'wb'))

    elif siting_parameters['solution_method']['MIRSA']['set']:

        custom_log(' MIRSA chosen to solve the IP. Opening a Julia instance.')
        params = siting_parameters['solution_method']['MIRSA']

        jl_dict = generate_jl_input(deployment_dict, site_coordinates)

        import julia
        j = julia.Julia(compiled_modules=False)
        from julia import Main
        Main.include("jl/SitingHeuristics.jl")

        start = time.time()
        jl_selected, jl_objective, jl_traj = Main.main_MIRSA(jl_dict['index_dict'], jl_dict['deployment_dict'],
                                                             criticality_data, c, params['neighborhood'],
                                                             params['no_iterations'], params['no_epochs'],
                                                             params['initial_temp'], params['no_runs'],
                                                             params['algorithm'])
        end = time.time()
        print(f"Average CPU time for c={c}: {round((end-start)/params['no_runs'], 1)} s")

        output_folder = init_folder(model_parameters, c, suffix=f"_MIRSA_{params['algorithm']}")

        with open(join(output_folder, 'config_model.yaml'), 'w') as outfile:
            yaml.dump(model_parameters, outfile, default_flow_style=False, sort_keys=False)
        with open(join(output_folder, 'config_techs.yaml'), 'w') as outfile:
            yaml.dump(tech_parameters, outfile, default_flow_style=False, sort_keys=False)

        pickle.dump(jl_selected, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(jl_objective, open(join(output_folder, 'objective_vector.p'), 'wb'))
        pickle.dump(jl_traj, open(join(output_folder, 'trajectory_matrix.p'), 'wb'))

    elif siting_parameters['solution_method']['RAND']['set']:
    
        custom_log(' Locations to be chosen via random search.')
        params = siting_parameters['solution_method']['RAND']
    
        jl_dict = generate_jl_input(deployment_dict, site_coordinates)
    
        import julia
        j = julia.Julia(compiled_modules=False)
        from julia import Main
        Main.include("jl/SitingHeuristics.jl")

        jl_selected, jl_objective = Main.main_RAND(jl_dict['deployment_dict'], criticality_data,
                                                   c, params['no_iterations'], params['no_runs'],
                                                   params['algorithm'])
    
        output_folder = init_folder(model_parameters, c, suffix='_RS')
    
        pickle.dump(jl_selected, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(jl_objective, open(join(output_folder, 'objective_vector.p'), 'wb'))

    elif siting_parameters['solution_method']['GRED_DET']['set']:

        params = siting_parameters['solution_method']['GRED_DET']
        custom_log(f" GRED_{params['algorithm']} chosen to solve the IP. Opening a Julia instance.")

        jl_dict = generate_jl_input(deployment_dict, site_coordinates)

        import julia
        j = julia.Julia(compiled_modules=False)
        from julia import Main
        Main.include("jl/SitingHeuristics.jl")

        start = time.time()
        jl_selected, jl_objective = Main.main_GRED(jl_dict['deployment_dict'], criticality_data, c,
                                                   params['no_runs'], params['p'], params['algorithm'])
        end = time.time()
        print(f"Average CPU time for c={c}: {round((end-start)/params['no_runs'], 1)} s")

        output_folder = init_folder(model_parameters, c, suffix=f"_GRED_{params['algorithm']}")

        pickle.dump(jl_selected, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(jl_objective, open(join(output_folder, 'objective_vector.p'), 'wb'))

    elif siting_parameters['solution_method']['GRED_STO']['set']:

        params = siting_parameters['solution_method']['GRED_STO']
        custom_log(f" GRED_{params['algorithm']} chosen to solve the IP. Opening a Julia instance.")

        jl_dict = generate_jl_input(deployment_dict, site_coordinates)

        import julia
        j = julia.Julia(compiled_modules=False)
        from julia import Main
        Main.include("jl/SitingHeuristics.jl")

        start = time.time()
        jl_selected, jl_objective = Main.main_GRED(jl_dict['deployment_dict'], criticality_data, c,
                                                   params['no_runs'], params['p'], params['algorithm'])
        end = time.time()
        print(f"Average CPU time for c={c}: {round((end-start)/params['no_runs'], 1)} s")

        output_folder = init_folder(model_parameters, c, suffix=f"_GRED_{params['algorithm']}_p{params['p']}")

        pickle.dump(jl_selected, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(jl_objective, open(join(output_folder, 'objective_vector.p'), 'wb'))

    elif siting_parameters['solution_method']['SGHLS']['set']:

        params = siting_parameters['solution_method']['SGHLS']
        custom_log(f" SHGLS_{params['algorithm']} chosen to solve the IP. Opening a Julia instance.")

        jl_dict = generate_jl_input(deployment_dict, site_coordinates)

        import julia
        j = julia.Julia(compiled_modules=False)
        from julia import Main
        Main.include("jl/SitingHeuristics.jl")

        start = time.time()
        jl_selected, jl_objective, jl_traj = Main.main_SGHLS(jl_dict['index_dict'], jl_dict['deployment_dict'],
                                                             criticality_data, c, params['neighborhood'],
                                                             params['no_iterations'], params['no_epochs'],
                                                             params['initial_temp'], params['p'],
                                                             params['no_runs_SGH'], params['no_runs_LS'],
                                                             params['algorithm'])
        end = time.time()
        print(f"Average CPU time for c={c}: {round((end-start)/params['no_runs_LS'], 1)} s")

        output_folder = init_folder(model_parameters, c, suffix=f"_SGHLS_{params['algorithm']}_p{params['p']}")

        pickle.dump(jl_selected, open(join(output_folder, 'solution_matrix.p'), 'wb'))
        pickle.dump(jl_objective, open(join(output_folder, 'objective_vector.p'), 'wb'))
        pickle.dump(jl_traj, open(join(output_folder, 'trajectory_matrix.p'), 'wb'))

    else:
        raise ValueError(' This solution method is not available. ')