From 2ac42537bcfce49f33ba61be776c9ebf3554f083 Mon Sep 17 00:00:00 2001 From: Will Usher Date: Mon, 18 Mar 2019 12:33:10 +0000 Subject: [PATCH 1/6] Update digital comms model code and data source --- provision/config.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provision/config.ini b/provision/config.ini index 71d5dfad..c9c695e8 100644 --- a/provision/config.ini +++ b/provision/config.ini @@ -22,11 +22,11 @@ remote_data=data/transport/transport_southampton_data_v2.0.0-alpha-5.zip local_dir=data/transport [digital-comms] -remote_data=releases/digital_comms/digital_comms_v0.2.0.zip +remote_data=releases/digital_comms/processed_data.zip local_dir=data/digital_comms -model_version=v0.2.0 +model_version=5538973b89e3d04d1d799aedfc112cee988572d7 [et-module] -model_version=25d25afd5df7e24588ade512db62f4a3ac0edc78 remote_data=data/et_module/et_module_v0.2.zip local_dir=data/et_module +model_version=25d25afd5df7e24588ade512db62f4a3ac0edc78 From 168cfd6ff7721fffa7a53dd4b08f9fd94250754f Mon Sep 17 00:00:00 2001 From: Will Usher Date: Tue, 19 Mar 2019 09:52:00 +0000 Subject: [PATCH 2/6] Updated DC run.py and configuration --- .../digital_comms_fixed_network.yml | 56 +-- models/digital_comms/run.py | 383 +++++++++++------- 2 files changed, 266 insertions(+), 173 deletions(-) diff --git a/config/sector_models/digital_comms_fixed_network.yml b/config/sector_models/digital_comms_fixed_network.yml index 419a2abc..8db12b08 100644 --- a/config/sector_models/digital_comms_fixed_network.yml +++ b/config/sector_models/digital_comms_fixed_network.yml @@ -23,7 +23,7 @@ parameters: - 1000 default: ../digital_comms/parameters/defaults.csv dims: [] - name: costs_links_fiber_meter + name: costs_links_fibre_meter unit: GBP - description: The cost of installing a copper link dtype: int @@ -420,133 +420,133 @@ outputs: dtype: int unit: Number of premises - name: interventions - dims: + dims: - national - annual dtype: int unit: assets - name: distribution_upgrades - dims: + dims: - broadband_distributions - annual dtype: int unit: GBP - name: distribution_upgrade_costs_fttp - dims: + dims: - broadband_distributions - annual dtype: int unit: GBP - name: distribution_upgrade_costs_fttdp - dims: + dims: - broadband_distributions - annual dtype: int unit: GBP - name: premises_upgrade_costs_fttp - dims: + dims: - broadband_distributions - annual dtype: int unit: GBP - name: premises_upgrade_costs_fttdp - dims: + dims: - broadband_distributions - annual dtype: int unit: GBP - name: premises_by_distribution - dims: + dims: - broadband_distributions - annual dtype: int - unit: premises + unit: premises - name: premises_adoption_desirability - dims: + dims: - national - annual dtype: int unit: premises - name: premises_connection_statistics - dims: + dims: - national - annual dtype: int unit: premises - name: premises_passed_with_fttp - dims: + dims: - national - annual dtype: int unit: premises - name: percentage_of_premises_passed_with_fttp - dims: + dims: - national - annual dtype: int - unit: premises + unit: premises - name: premises_connected_with_fttp - dims: + dims: - national - annual dtype: int unit: premises - name: percentage_of_premises_connected_with_fttp - dims: + dims: - national - annual dtype: int - unit: premises + unit: premises - name: premises_passed_with_fttdp - dims: + dims: - national - annual dtype: int unit: premises - name: percentage_of_premises_passed_with_fttdp - dims: + dims: - national - annual dtype: int - unit: premises + unit: premises - name: premises_connected_with_fttdp - dims: + dims: - national - annual dtype: int unit: premises - name: percentage_of_premises_connected_with_fttdp - dims: + dims: - national - annual dtype: int - unit: premises + unit: premises - name: percentage_of_premises_with_fttc - dims: + dims: - national - annual dtype: int unit: premises - name: lad_premises_with_fttp - dims: + dims: - lad_uk_2016 - annual dtype: int unit: premises - name: lad_premises_with_fttdp - dims: + dims: - lad_uk_2016 - annual dtype: int unit: premises - name: lad_premises_with_fttc - dims: + dims: - lad_uk_2016 - annual dtype: int unit: premises - name: lad_premises_with_adsl - dims: + dims: - lad_uk_2016 - annual dtype: int diff --git a/models/digital_comms/run.py b/models/digital_comms/run.py index 3c9e7f92..51c7e742 100644 --- a/models/digital_comms/run.py +++ b/models/digital_comms/run.py @@ -4,25 +4,28 @@ import csv import os -#from memory_profiler import profile -#from pyinstrument import Profiler -import fiona -import numpy as np +import fiona # type: ignore +import numpy as np # type: ignore -from digital_comms.fixed_network.model import ICTManager +from digital_comms.fixed_network.model import NetworkManager from digital_comms.fixed_network.interventions import decide_interventions from digital_comms.fixed_network.adoption import update_adoption_desirability +from digital_comms.runner import read_csv, read_assets, read_links -from smif.model.sector_model import SectorModel +from smif.model.sector_model import SectorModel # type: ignore +import smif -# numpy options -np.set_printoptions(threshold=10) # configure profiling with environment variable PROFILE = False if 'PROFILE_DC' in os.environ and os.environ['PROFILE_DC'] == "1": PROFILE = True + try: + from memory_profiler import profile + from pyinstrument import Profiler + except ImportError: + pass def memprofile(func): @@ -55,16 +58,11 @@ class DigitalCommsWrapper(SectorModel): """ def __init__(self, name): super().__init__(name) - - self.user_data = {} - - def initialise(self, initial_conditions): - print('initialise') + self.system = None @cpuprofile @memprofile - def before_model_run(self, data_handle): - print('before model run') + def before_model_run(self, data_handle : smif.data_layer.DataHandle): """Implement this method to conduct pre-model run tasks Arguments @@ -73,6 +71,7 @@ def before_model_run(self, data_handle): Access parameter values (before any model is run, no dependency input data or state is guaranteed to be available) """ + print('before model run') # Get wrapper configuration path_main = os.path.dirname(os.path.abspath(__file__)) @@ -81,80 +80,92 @@ def before_model_run(self, data_handle): data_path = config['PATHS']['path_local_data'] # Get modelrun configuration - parameters = data_handle.get_parameters() - parameters = {parameter: int(parameters[parameter].as_ndarray()) for parameter in parameters} + read_only_parameters = data_handle.get_parameters() - # Get strategy - if parameters['technology_strategy'] == 0: - parameters['technology_strategy'] = 'fttdp_subsidised_rollout_per_distribution' + parameters = {} + for name, dataarray in read_only_parameters.items(): + parameters[name] = dataarray.data + + self.logger.debug(parameters) # Load assets - assets = {} - assets['premises'] = read_shapefile(os.path.join(data_path, 'assets_layer5_premises.shp')) - assets['distributions'] = read_shapefile(os.path.join(data_path, 'assets_layer4_distributions.shp')) - assets['cabinets'] = read_shapefile(os.path.join(data_path, 'assets_layer3_cabinets.shp')) - assets['exchanges'] = read_shapefile(os.path.join(data_path, 'assets_layer2_exchanges.shp')) + assets = read_assets(data_path) # Load links - links = [] - links.extend(read_shapefile(os.path.join(data_path, 'links_layer5_premises.shp'))) - links.extend(read_shapefile(os.path.join(data_path, 'links_layer4_distributions.shp'))) - links.extend(read_shapefile(os.path.join(data_path, 'links_layer3_cabinets.shp'))) + links = read_links(data_path) self.logger.info("DigitalCommsWrapper - Intitialise system") - self.system = ICTManager(assets, links, parameters) + self.system = NetworkManager(assets, links, parameters) print('only distribution points with a benefit cost ratio > 1 can be upgraded') print('model rollout is constrained by the adoption desirability set by scenario') - @cpuprofile @memprofile - def simulate(self, data_handle): + def simulate(self, data): + """Implement smif.SectorModel simulate + """ # ----- # Start # ----- + data_handle = data now = data_handle.current_timestep self.logger.info("DigitalCommsWrapper received inputs in %s", now) # Set global parameters - STRATEGY = int(data_handle.get_parameter('technology_strategy').as_ndarray()) - if STRATEGY == 0: - STRATEGY = 'fttdp_subsidised_rollout_per_distribution' + technology_strategy = data_handle.get_parameter('technology_strategy').data + - TECH = STRATEGY.split("_")[0] + technology = technology_strategy.split('_', 1)[0] + policy = technology_strategy.split('_', 1)[1] # ----------------------- # Get scenario adoption rate # ----------------------- print("-------------------") - print("Running", TECH, STRATEGY, data_handle.current_timestep) + print("Running", technology, policy, data_handle.current_timestep) print("-------------------") - annual_adoption_rate = data_handle.get_data('adoption').data[0] - adoption_desirability = [premise for premise in self.system._premises if premise.adoption_desirability is True] + annual_adoption_rate = data_handle.get_data('adoption') + adoption_desirability = [ + premise + for premise in self.system._premises + if premise.adoption_desirability is True + ] total_premises = [premise for premise in self.system._premises] - adoption_desirability_percentage = (len(adoption_desirability) / len(total_premises) * 100) + adoption_desirability_percentage = ( + len(adoption_desirability) / len(total_premises) * 100) percentage_annual_increase = annual_adoption_rate - adoption_desirability_percentage percentage_annual_increase = round(float(percentage_annual_increase), 1) - print("* {} annual_adoption_rate is {} %".format(TECH, percentage_annual_increase)) + print("* {} annual_adoption_rate is {} %".format(technology, percentage_annual_increase)) # ----------------------- # Run fixed network model # ----------------------- self.logger.info("DigitalCommsWrapper - Update adoption status on premises") - self.system.update_adoption_desirability = update_adoption_desirability(self.system, percentage_annual_increase) + self.system.update_adoption_desirability = update_adoption_desirability( + self.system, percentage_annual_increase) premises_adoption_desirability_ids = self.system.update_adoption_desirability - MAXIMUM_ADOPTION = len(premises_adoption_desirability_ids) + sum(getattr(premise, TECH) for premise in self.system._premises) - # print("// length of premises_adoption_desirability_ids is {}".format(len(premises_adoption_desirability_ids)+1)) - # print("// sum of premises by tech {}".format(sum(getattr(premise, TECH) for premise in self.system._premises))) - # print("// MAXIMUM_ADOPTION is {}".format(MAXIMUM_ADOPTION)) + adoption_cap = len(premises_adoption_desirability_ids) + \ + sum(getattr(premise, technology) for premise in self.system._premises) + # print("// length of premises_adoption_desirability_ids is {}".format( + # len(premises_adoption_desirability_ids)+1)) + # print("// sum of premises by tech {}".format( + # sum(getattr(premise, technology) for premise in self.system._premises))) + # print("// adoption_cap is {}".format(adoption_cap)) self.logger.info("DigitalCommsWrapper - Decide interventions") - interventions, budget, spend, match_funding_spend, subsidised_spend = decide_interventions( - STRATEGY, int(data_handle.get_parameter('annual_budget').data), int(data_handle.get_parameter('service_obligation_capacity').data), - self.system, now, MAXIMUM_ADOPTION, int(data_handle.get_parameter('telco_match_funding').data), - int(data_handle.get_parameter('subsidy').data)) + interventions = decide_interventions( + self.system, + now, + technology, + policy, + data_handle.get_parameter('annual_budget'), + adoption_cap, + data_handle.get_parameter('subsidy'), + data_handle.get_parameter('telco_match_funding'), + data_handle.get_parameter('service_obligation_capacity'), + ) self.logger.info("DigitalCommsWrapper - Upgrading system") self.system.upgrade(interventions) @@ -162,106 +173,102 @@ def simulate(self, data_handle): # ------------- # Write outputs # ------------- - interventions_lut = {intervention[0]:intervention for intervention in interventions} - - distribution_upgrades = np.empty((self.system.number_of_assets['distributions'],1)) - for idx, distribution in enumerate(self.outputs['distribution_upgrades'].dim_coords('broadband_distributions').ids): - distribution_upgrades[idx, 0] = interventions_lut[distribution][2] if distribution in interventions_lut else 0 + interventions_lut = {intervention[0]: intervention for intervention in interventions} + + distribution_upgrades = np.empty( + (self.system.number_of_assets['distributions'], 1)) + distribution_names = data_handle.get_region_names('broadband_distributions') + for idx, distribution in enumerate(distribution_names): + distribution_upgrades[idx, 0] = \ + interventions_lut[distribution][2] if distribution in interventions_lut else 0 data_handle.set_results('distribution_upgrades', distribution_upgrades) - premises_by_distribution = np.empty((self.system.number_of_assets['distributions'],1)) + premises_by_distribution = np.empty((self.system.number_of_assets['distributions'], 1)) for idx, distribution in enumerate(self.system.assets['distributions']): premises_by_distribution[idx, 0] = len(distribution._clients) data_handle.set_results('premises_by_distribution', premises_by_distribution) - print("* {} premises adoption desirability is {}".format(TECH, (len(premises_adoption_desirability_ids)))) - premises_wanting_to_adopt = np.empty((1,1)) + print("* {} premises adoption desirability is {}".format( + technology, (len(premises_adoption_desirability_ids)))) + premises_wanting_to_adopt = np.empty((1, 1)) premises_wanting_to_adopt[0, 0] = len(premises_adoption_desirability_ids) data_handle.set_results('premises_adoption_desirability', premises_wanting_to_adopt) - if TECH == 'fttp': - - distribution_upgrade_costs_fttp = np.empty((self.system.number_of_assets['distributions'],1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - distribution_upgrade_costs_fttp[idx, 0] = distribution.upgrade_costs['fttp'] - data_handle.set_results('distribution_upgrade_costs_fttp', distribution_upgrade_costs_fttp) - - upgrade_cost_per_premises_fttp = np.empty((self.system.number_of_assets['distributions'],1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - if len(distribution._clients) > 0: - upgrade_cost_per_premises_fttp[idx, 0] = distribution.upgrade_costs['fttp'] / len(distribution._clients) - else: - upgrade_cost_per_premises_fttp[idx, 0] = 0 - data_handle.set_results('premises_upgrade_costs_fttp', upgrade_cost_per_premises_fttp) - - premises_passed_with_fttp = np.empty((1,1)) - premises_passed_with_fttp[0, 0] = sum(premise.fttp for premise in self.system._premises) - print("* fttp premises passed {}".format(premises_passed_with_fttp)) - data_handle.set_results('premises_passed_with_fttp', premises_passed_with_fttp) - - percentage_of_premises_passed_with_fttp = np.empty((1,1)) - percentage_of_premises_passed_with_fttp[0, 0] = round((sum(premise.fttp for premise in self.system._premises) / len(self.system._premises)*100),2) - print("* fttp % premises passed {}".format(percentage_of_premises_passed_with_fttp)) - data_handle.set_results('percentage_of_premises_passed_with_fttp', percentage_of_premises_passed_with_fttp) - - premises_connected_with_fttp = np.empty((1,1)) - premises_connected_with_fttp[0, 0] = sum(premise.fttp for premise in self.system._premises if premise.adoption_desirability == True) - print("* fttp premises connected {}".format(premises_connected_with_fttp)) - data_handle.set_results('premises_connected_with_fttp', premises_connected_with_fttp) - - percentage_of_premises_connected_with_fttp = np.empty((1,1)) - percentage_of_premises_connected_with_fttp[0, 0] = round((sum(premise.fttp for premise in self.system._premises if premise.adoption_desirability == True) / len(self.system._premises)*100),2) - print("* fttp % premises connected {}".format(percentage_of_premises_connected_with_fttp)) - data_handle.set_results('percentage_of_premises_connected_with_fttp', percentage_of_premises_connected_with_fttp) - - if TECH == 'fttdp': - - distribution_upgrade_costs_fttdp = np.empty((self.system.number_of_assets['distributions'],1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - distribution_upgrade_costs_fttdp[idx, 0] = distribution.upgrade_costs['fttdp'] - data_handle.set_results('distribution_upgrade_costs_fttdp', distribution_upgrade_costs_fttdp) - - upgrade_cost_per_premises_fttdp = np.empty((self.system.number_of_assets['distributions'],1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - if len(distribution._clients) > 0: - upgrade_cost_per_premises_fttdp[idx, 0] = distribution.upgrade_costs['fttdp'] / len(distribution._clients) - else: - upgrade_cost_per_premises_fttdp[idx, 0] = 0 - data_handle.set_results('premises_upgrade_costs_fttdp', upgrade_cost_per_premises_fttdp) - - # premises_with_fttdp = np.empty((1,1)) - # premises_with_fttdp[0, 0] = sum(premise.fttdp for premise in self.system._premises) - # print("* fttdp premises passed {}".format(premises_with_fttdp)) - # data_handle.set_results('premises_with_fttdp', premises_with_fttdp) - - premises_passed_with_fttdp = np.empty((1,1)) - premises_passed_with_fttdp[0, 0] = sum(premise.fttdp for premise in self.system._premises) - print("* fttdp premises passed {}".format(premises_passed_with_fttdp)) - data_handle.set_results('premises_passed_with_fttdp', premises_passed_with_fttdp) - - # percentage_of_premises_with_fttdp = np.empty((1,1)) - # percentage_of_premises_with_fttdp[0, 0] = round((sum(premise.fttdp for premise in self.system._premises) / len(self.system._premises)*100),2) - # print("* fttdp % premises passed {}".format(percentage_of_premises_with_fttdp)) - # data_handle.set_results('premises_with_fttdp', percentage_of_premises_with_fttdp) - - percentage_of_premises_passed_with_fttdp = np.empty((1,1)) - percentage_of_premises_passed_with_fttdp[0, 0] = round((sum(premise.fttdp for premise in self.system._premises) / len(self.system._premises)*100),2) - print("* fttdp % premises passed {}".format(percentage_of_premises_passed_with_fttdp)) - data_handle.set_results('percentage_of_premises_passed_with_fttdp', percentage_of_premises_passed_with_fttdp) - - premises_connected_with_fttdp = np.empty((1,1)) - premises_connected_with_fttdp[0, 0] = sum(premise.fttdp for premise in self.system._premises if premise.adoption_desirability == True) - print("* fttdp premises connected {}".format(premises_connected_with_fttdp)) - data_handle.set_results('premises_connected_with_fttdp', premises_connected_with_fttdp) - - percentage_of_premises_connected_with_fttdp = np.empty((1,1)) - percentage_of_premises_connected_with_fttdp[0, 0] = round((sum(premise.fttdp for premise in self.system._premises if premise.adoption_desirability == True) / len(self.system._premises)*100),2) - print("* fttdp % premises connected {}".format(percentage_of_premises_connected_with_fttdp)) - data_handle.set_results('percentage_of_premises_connected_with_fttdp', percentage_of_premises_connected_with_fttdp) + distribution_upgrade_costs = ('distribution_upgrade_costs_' + str(technology)) + distribution_upgrade_costs = np.empty( + (self.system.number_of_assets['distributions'], 1)) + for idx, distribution in enumerate(self.system.assets['distributions']): + distribution_upgrade_costs[idx, 0] = distribution.upgrade_costs[technology] + data_handle.set_results(('distribution_upgrade_costs_' + + str(technology)), distribution_upgrade_costs) - # Regional output + upgrade_cost_per_premises = ('upgrade_cost_per_premises_' + str(technology)) + upgrade_cost_per_premises = np.empty( + (self.system.number_of_assets['distributions'], 1)) + for idx, distribution in enumerate(self.system.assets['distributions']): + if distribution._clients: + upgrade_cost_per_premises[idx, 0] = \ + distribution.upgrade_costs[technology] / len(distribution._clients) + else: + upgrade_cost_per_premises[idx, 0] = 0 + data_handle.set_results(('premises_upgrade_costs_' + str(technology)), + upgrade_cost_per_premises) + + # premises passed + premises_passed = ('premises_passed_with_' + str(technology)) + premises_passed = np.empty((1, 1)) + premises_passed[0, 0] = sum(getattr(premise, technology) + for premise in self.system._premises) + print("* {} premises passed {}".format(technology, premises_passed)) + data_handle.set_results(('premises_passed_with_' + str(technology)), premises_passed) + + percentage_of_premises_passed = ('percentage_of_premises_passed_with_' + str(technology)) + percentage_of_premises_passed = np.empty((1, 1)) + percentage_of_premises_passed[0, 0] = round( + ( + sum(getattr(premise, technology) for premise in self.system._premises) + / len(self.system._premises) + * 100 + ), + 2) + print("* {} percentage of premises passed {}".format( + technology, percentage_of_premises_passed)) + data_handle.set_results( + 'percentage_of_premises_passed_with_' + str(technology), + percentage_of_premises_passed) + + # premises connected + premises_connected = ('premises_connected_with_' + str(technology)) + premises_connected = np.empty((1, 1)) + premises_connected[0, 0] = sum( + getattr(premise, technology) + for premise in self.system._premises + if premise.adoption_desirability + ) + print("* {} premises connected {}".format(technology, premises_connected)) + data_handle.set_results(('premises_connected_with_' + str(technology)), premises_connected) + + percentage_of_premises_connected = ( + 'percentage_of_premises_connected_with_' + str(technology)) + percentage_of_premises_connected = np.empty((1, 1)) + percentage_of_premises_connected[0, 0] = round( + ( + sum( + getattr(premise, technology) + for premise in self.system._premises + if premise.adoption_desirability + ) + / len(self.system._premises) + * 100 + ), + 2) + print("* {} percentage of premises connected {}".format( + technology, percentage_of_premises_connected)) + data_handle.set_results(('percentage_of_premises_connected_with_' + str(technology)), + percentage_of_premises_connected) - lad_names = self.outputs['lad_premises_with_fttp'].dim_coords('lad_uk_2016').ids + # Regional output + lad_names = self.get_region_names('lad2016') num_lads = len(lad_names) num_fttp = np.zeros((num_lads, 1)) num_fttdp = np.zeros((num_lads, 1)) @@ -280,18 +287,104 @@ def simulate(self, data_handle): data_handle.set_results('lad_premises_with_fttp', num_fttp) data_handle.set_results('lad_premises_with_fttdp', num_fttdp) - # data_handle.set_results('lad_premises_with_fttc', num_fttc) - # data_handle.set_results('lad_premises_with_adsl', num_adsl) + + # get cambridge exchange data + if policy == 'fttp_rollout_per_distribution' and technology == 'fttp': + + path_main = os.path.dirname(os.path.abspath(__file__)) + config = configparser.ConfigParser() + config.read(os.path.join(path_main, 'wrapperconfig.ini')) + base_path = config['PATHS']['path_export_data'] + + def csv_writer(data, filename, fieldnames): + with open(os.path.join(base_path, filename), 'w') as csv_file: + writer = csv.DictWriter(csv_file, fieldnames, lineterminator='\n') + writer.writeheader() + writer.writerows(data) + + def write_out_upgrades(data): + export_data = [] + for datum in data: + export_data.append({ + 'id': datum.id, + 'upgrade': datum.fttp, + 'year': now + }) + return export_data + + # get exchanges + exchange = [ + exchange + for exchange in self.system._exchanges + if exchange.id == 'exchange_EACAM' + ][0] + + # get cabinets + cabinets = exchange._clients + cabinet_export_data = write_out_upgrades(cabinets) + + # get distributions + distributions = [] + for cabinet in cabinets: + distributions.extend(cabinet._clients) + distribution_export_data = write_out_upgrades(distributions) + + # get premises + premises = [] + for distribution in distributions: + premises.extend(distribution._clients) + + premises_export_data = [] + for premise in premises: + premises_export_data.append({ + 'id': premise.id, + 'adoption_desirability': premise.adoption_desirability, + 'premises_passed': premise.fttp, + 'year': now + }) + + # get exchange to cabinet links + exchange_to_cabinet_links = [ + link + for link in self.system._links_from_cabinets + if link.dest == 'exchange_EACAM' + ] + + # get cabinet to dist point links + cab_to_dist_point_links = exchange_to_cabinet_links.origin + + # get distributions + cab_to_dist_point_links = [] + for link in cab_to_dist_point_links: + cab_to_dist_point_links.extend(link.origin) + print(cab_to_dist_point_links) + + # set fieldnames + generic_fieldnames = ['id', 'upgrade', 'year'] + premises_fieldnames = ['id', 'adoption_desirability', 'premises_passed', 'year'] + + # write out + csv_writer( + cabinet_export_data, + 'cabinet_data{}.csv'.format(now), + generic_fieldnames) + csv_writer( + distribution_export_data, + 'distribution_data{}.csv'.format(now), + generic_fieldnames) + csv_writer( + premises_export_data, + 'premises_data{}.csv'.format(now), + premises_fieldnames) # ---- # Exit # ---- - self.logger.info("DigitalCommsWrapper produced outputs in %s", - now) + self.logger.info("DigitalCommsWrapper produced outputs in %s", now) - def extract_obj(self, results): - return 0 def read_shapefile(file): + """Read properties for all features in a shapefile + """ with fiona.open(file, 'r') as source: return [f['properties'] for f in source] From d409bd386ab882bbd39bfc4a4f5da33aa3424066 Mon Sep 17 00:00:00 2001 From: Will Usher Date: Tue, 19 Mar 2019 13:30:14 +0000 Subject: [PATCH 3/6] Remove adoption scenarios from main repo --- data/scenarios/fttdp_baseline_adoption.csv | 13 ------------- data/scenarios/fttdp_high_adoption.csv | 13 ------------- data/scenarios/fttdp_low_adoption.csv | 13 ------------- data/scenarios/fttp_baseline_adoption.csv | 13 ------------- data/scenarios/fttp_baseline_adoption_test.csv | 14 -------------- data/scenarios/fttp_high_adoption.csv | 13 ------------- data/scenarios/fttp_low_adoption.csv | 13 ------------- 7 files changed, 92 deletions(-) delete mode 100644 data/scenarios/fttdp_baseline_adoption.csv delete mode 100644 data/scenarios/fttdp_high_adoption.csv delete mode 100644 data/scenarios/fttdp_low_adoption.csv delete mode 100644 data/scenarios/fttp_baseline_adoption.csv delete mode 100644 data/scenarios/fttp_baseline_adoption_test.csv delete mode 100644 data/scenarios/fttp_high_adoption.csv delete mode 100644 data/scenarios/fttp_low_adoption.csv diff --git a/data/scenarios/fttdp_baseline_adoption.csv b/data/scenarios/fttdp_baseline_adoption.csv deleted file mode 100644 index e0fa2475..00000000 --- a/data/scenarios/fttdp_baseline_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,3 -2021,national,1,5 -2022,national,1,9 -2023,national,1,14 -2024,national,1,21 -2025,national,1,31 -2026,national,1,42 -2027,national,1,53 -2028,national,1,62 -2029,national,1,69 -2030,national,1,73 diff --git a/data/scenarios/fttdp_high_adoption.csv b/data/scenarios/fttdp_high_adoption.csv deleted file mode 100644 index 86a778ba..00000000 --- a/data/scenarios/fttdp_high_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,4.314770308 -2021,national,1,8.670076716 -2022,national,1,16.57138402 -2023,national,1,29.09721637 -2024,national,1,45.25567893 -2025,national,1,61.34847475 -2026,national,1,73.7336888 -2027,national,1,81.50636173 -2028,national,1,85.7776379 -2029,national,1,87.95487229 -2030,national,1,89.02222681 diff --git a/data/scenarios/fttdp_low_adoption.csv b/data/scenarios/fttdp_low_adoption.csv deleted file mode 100644 index d4dea672..00000000 --- a/data/scenarios/fttdp_low_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,2 -2021,national,1,3 -2022,national,1,5 -2023,national,1,7 -2024,national,1,10 -2025,national,1,13 -2026,national,1,18 -2027,national,1,24 -2028,national,1,31 -2029,national,1,38 -2030,national,1,45 diff --git a/data/scenarios/fttp_baseline_adoption.csv b/data/scenarios/fttp_baseline_adoption.csv deleted file mode 100644 index e0fa2475..00000000 --- a/data/scenarios/fttp_baseline_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,3 -2021,national,1,5 -2022,national,1,9 -2023,national,1,14 -2024,national,1,21 -2025,national,1,31 -2026,national,1,42 -2027,national,1,53 -2028,national,1,62 -2029,national,1,69 -2030,national,1,73 diff --git a/data/scenarios/fttp_baseline_adoption_test.csv b/data/scenarios/fttp_baseline_adoption_test.csv deleted file mode 100644 index 780dc5de..00000000 --- a/data/scenarios/fttp_baseline_adoption_test.csv +++ /dev/null @@ -1,14 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,5 -2020,national,1,10 -2021,national,1,15 -2022,national,1,20 -2023,national,1,25 -2024,national,1,30 -2025,national,1,35 -2026,national,1,40 -2027,national,1,45 -2028,national,1,50 -2029,national,1,55 -2030,national,1,60 -2031,national,1,65 diff --git a/data/scenarios/fttp_high_adoption.csv b/data/scenarios/fttp_high_adoption.csv deleted file mode 100644 index 86a778ba..00000000 --- a/data/scenarios/fttp_high_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,4.314770308 -2021,national,1,8.670076716 -2022,national,1,16.57138402 -2023,national,1,29.09721637 -2024,national,1,45.25567893 -2025,national,1,61.34847475 -2026,national,1,73.7336888 -2027,national,1,81.50636173 -2028,national,1,85.7776379 -2029,national,1,87.95487229 -2030,national,1,89.02222681 diff --git a/data/scenarios/fttp_low_adoption.csv b/data/scenarios/fttp_low_adoption.csv deleted file mode 100644 index d4dea672..00000000 --- a/data/scenarios/fttp_low_adoption.csv +++ /dev/null @@ -1,13 +0,0 @@ -timestep,national,annual,adoption -2019,national,1,1 -2020,national,1,2 -2021,national,1,3 -2022,national,1,5 -2023,national,1,7 -2024,national,1,10 -2025,national,1,13 -2026,national,1,18 -2027,national,1,24 -2028,national,1,31 -2029,national,1,38 -2030,national,1,45 From 5c9f4825fc995b59ae0029c2b6ab4075626bac22 Mon Sep 17 00:00:00 2001 From: Will Usher Date: Tue, 19 Mar 2019 13:33:44 +0000 Subject: [PATCH 4/6] Changed path to adoption scenarios to data/digital_comms/scenarios --- config/scenarios/adoption.yml | 12 ++++++------ models/digital_comms/run.py | 19 ++++--------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/config/scenarios/adoption.yml b/config/scenarios/adoption.yml index 3da0e411..fc2a1820 100644 --- a/config/scenarios/adoption.yml +++ b/config/scenarios/adoption.yml @@ -15,26 +15,26 @@ provides: variants: - description: Baseline FTTP adoption for the UK data: - adoption: fttp_baseline_adoption.csv + adoption: ../digital_comms/scenarios/fttp_baseline_adoption.csv name: fttp_baseline_adoption - description: High FTTP adoption for the UK data: - adoption: fttp_high_adoption.csv + adoption: ../digital_comms/scenarios/fttp_high_adoption.csv name: fttp_high_adoption - description: Low FTTP adoption for the UK data: - adoption: fttp_low_adoption.csv + adoption: ../digital_comms/scenarios/fttp_low_adoption.csv name: fttp_low_adoption - description: Baseline FTTDP adoption for the UK data: - adoption: fttdp_baseline_adoption.csv + adoption: ../digital_comms/scenarios/fttdp_baseline_adoption.csv name: fttdp_baseline_adoption - description: High FTTDP adoption for the UK data: - adoption: fttdp_high_adoption.csv + adoption: ../digital_comms/scenarios/fttdp_high_adoption.csv name: fttdp_high_adoption - description: Low FTTDP adoption for the UK data: - adoption: fttdp_low_adoption.csv + adoption: ../digital_comms/scenarios/fttdp_low_adoption.csv name: fttdp_low_adoption name: adoption diff --git a/models/digital_comms/run.py b/models/digital_comms/run.py index 51c7e742..93479fd5 100644 --- a/models/digital_comms/run.py +++ b/models/digital_comms/run.py @@ -102,29 +102,22 @@ def before_model_run(self, data_handle : smif.data_layer.DataHandle): @cpuprofile @memprofile - def simulate(self, data): + def simulate(self, data_handle : smif.data_layer.DataHandle): """Implement smif.SectorModel simulate """ # ----- # Start # ----- - data_handle = data + data_handle = data_handle now = data_handle.current_timestep self.logger.info("DigitalCommsWrapper received inputs in %s", now) # Set global parameters technology_strategy = data_handle.get_parameter('technology_strategy').data - - technology = technology_strategy.split('_', 1)[0] - policy = technology_strategy.split('_', 1)[1] - # ----------------------- # Get scenario adoption rate # ----------------------- - print("-------------------") - print("Running", technology, policy, data_handle.current_timestep) - print("-------------------") annual_adoption_rate = data_handle.get_data('adoption') adoption_desirability = [ premise @@ -136,7 +129,6 @@ def simulate(self, data): len(adoption_desirability) / len(total_premises) * 100) percentage_annual_increase = annual_adoption_rate - adoption_desirability_percentage percentage_annual_increase = round(float(percentage_annual_increase), 1) - print("* {} annual_adoption_rate is {} %".format(technology, percentage_annual_increase)) # ----------------------- # Run fixed network model @@ -148,12 +140,8 @@ def simulate(self, data): adoption_cap = len(premises_adoption_desirability_ids) + \ sum(getattr(premise, technology) for premise in self.system._premises) - # print("// length of premises_adoption_desirability_ids is {}".format( - # len(premises_adoption_desirability_ids)+1)) - # print("// sum of premises by tech {}".format( - # sum(getattr(premise, technology) for premise in self.system._premises))) - # print("// adoption_cap is {}".format(adoption_cap)) + # TODO: Move this into decision module self.logger.info("DigitalCommsWrapper - Decide interventions") interventions = decide_interventions( self.system, @@ -173,6 +161,7 @@ def simulate(self, data): # ------------- # Write outputs # ------------- + # TODO: Change this into set_results calls interventions_lut = {intervention[0]: intervention for intervention in interventions} distribution_upgrades = np.empty( From 0cca069df7db326c48986dce81792446fa949e78 Mon Sep 17 00:00:00 2001 From: Will Usher Date: Wed, 20 Mar 2019 11:12:11 +0000 Subject: [PATCH 5/6] Simplified wrapper, moved decision logic - Simplified wrapper by moving all of the decision logic into a newly created decisions module - Currently blocked by need to import adoption scenario data into decisions module - Need to better understand dimensionality of technology and distribution points and work out how to pass these as interventions (if appropriate) to the decision module --- config/model_runs/digital_comms_test.yml | 6 +- models/digital_comms/run.py | 315 +---------------------- planning/digital_decisions.py | 80 ++++++ 3 files changed, 98 insertions(+), 303 deletions(-) create mode 100644 planning/digital_decisions.py diff --git a/config/model_runs/digital_comms_test.yml b/config/model_runs/digital_comms_test.yml index 451aa731..0fb2dd02 100644 --- a/config/model_runs/digital_comms_test.yml +++ b/config/model_runs/digital_comms_test.yml @@ -6,7 +6,11 @@ scenarios: adoption: fttp_baseline_adoption sos_model: digital_comms_fixed_only stamp: '2018-05-01T12:36:34.374Z' -strategies: [] +strategies: +- type: rule-based + description: reduce emissions + path: planning/digital_decisions.py + classname: DigitalDecisions timesteps: - 2019 - 2020 diff --git a/models/digital_comms/run.py b/models/digital_comms/run.py index 93479fd5..7a5260b7 100644 --- a/models/digital_comms/run.py +++ b/models/digital_comms/run.py @@ -14,44 +14,7 @@ from digital_comms.runner import read_csv, read_assets, read_links from smif.model.sector_model import SectorModel # type: ignore -import smif - - -# configure profiling with environment variable -PROFILE = False -if 'PROFILE_DC' in os.environ and os.environ['PROFILE_DC'] == "1": - PROFILE = True - try: - from memory_profiler import profile - from pyinstrument import Profiler - except ImportError: - pass - - -def memprofile(func): - """Decorator - profile memory usage if profiling is enabled - """ - def wrapper(*args, **kwargs): - if PROFILE: - profile(func, precision=1)(*args, **kwargs) - else: - func(*args, **kwargs) - return wrapper - - -def cpuprofile(func): - """Decorator - profile cpu usage - """ - def wrapper(*args, **kwargs): - if PROFILE: - profiler = Profiler() - profiler.start() - func(*args, **kwargs) - if PROFILE: - profiler.stop() - print(profiler.output_text(unicode=False, color=True)) - return wrapper - +from smif.data_layer import DataHandle class DigitalCommsWrapper(SectorModel): """Digital model @@ -60,9 +23,7 @@ def __init__(self, name): super().__init__(name) self.system = None - @cpuprofile - @memprofile - def before_model_run(self, data_handle : smif.data_layer.DataHandle): + def before_model_run(self, data_handle : DataHandle): """Implement this method to conduct pre-model run tasks Arguments @@ -100,9 +61,7 @@ def before_model_run(self, data_handle : smif.data_layer.DataHandle): print('only distribution points with a benefit cost ratio > 1 can be upgraded') print('model rollout is constrained by the adoption desirability set by scenario') - @cpuprofile - @memprofile - def simulate(self, data_handle : smif.data_layer.DataHandle): + def simulate(self, data_handle : DataHandle): """Implement smif.SectorModel simulate """ # ----- @@ -112,268 +71,20 @@ def simulate(self, data_handle : smif.data_layer.DataHandle): now = data_handle.current_timestep self.logger.info("DigitalCommsWrapper received inputs in %s", now) - # Set global parameters - technology_strategy = data_handle.get_parameter('technology_strategy').data - - # ----------------------- - # Get scenario adoption rate - # ----------------------- - annual_adoption_rate = data_handle.get_data('adoption') - adoption_desirability = [ - premise - for premise in self.system._premises - if premise.adoption_desirability is True - ] - total_premises = [premise for premise in self.system._premises] - adoption_desirability_percentage = ( - len(adoption_desirability) / len(total_premises) * 100) - percentage_annual_increase = annual_adoption_rate - adoption_desirability_percentage - percentage_annual_increase = round(float(percentage_annual_increase), 1) - - # ----------------------- - # Run fixed network model - # ----------------------- - self.logger.info("DigitalCommsWrapper - Update adoption status on premises") - self.system.update_adoption_desirability = update_adoption_desirability( - self.system, percentage_annual_increase) - premises_adoption_desirability_ids = self.system.update_adoption_desirability + interventions = data_handle.get_current_interventions() - adoption_cap = len(premises_adoption_desirability_ids) + \ - sum(getattr(premise, technology) for premise in self.system._premises) - - # TODO: Move this into decision module - self.logger.info("DigitalCommsWrapper - Decide interventions") - interventions = decide_interventions( - self.system, - now, - technology, - policy, - data_handle.get_parameter('annual_budget'), - adoption_cap, - data_handle.get_parameter('subsidy'), - data_handle.get_parameter('telco_match_funding'), - data_handle.get_parameter('service_obligation_capacity'), - ) - - self.logger.info("DigitalCommsWrapper - Upgrading system") + self.logger.debug("DigitalCommsWrapper - Upgrading system") self.system.upgrade(interventions) # ------------- # Write outputs # ------------- - # TODO: Change this into set_results calls - interventions_lut = {intervention[0]: intervention for intervention in interventions} - - distribution_upgrades = np.empty( - (self.system.number_of_assets['distributions'], 1)) - distribution_names = data_handle.get_region_names('broadband_distributions') - for idx, distribution in enumerate(distribution_names): - distribution_upgrades[idx, 0] = \ - interventions_lut[distribution][2] if distribution in interventions_lut else 0 - data_handle.set_results('distribution_upgrades', distribution_upgrades) - - premises_by_distribution = np.empty((self.system.number_of_assets['distributions'], 1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - premises_by_distribution[idx, 0] = len(distribution._clients) - data_handle.set_results('premises_by_distribution', premises_by_distribution) - - print("* {} premises adoption desirability is {}".format( - technology, (len(premises_adoption_desirability_ids)))) - premises_wanting_to_adopt = np.empty((1, 1)) - premises_wanting_to_adopt[0, 0] = len(premises_adoption_desirability_ids) - data_handle.set_results('premises_adoption_desirability', premises_wanting_to_adopt) - - distribution_upgrade_costs = ('distribution_upgrade_costs_' + str(technology)) - distribution_upgrade_costs = np.empty( - (self.system.number_of_assets['distributions'], 1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - distribution_upgrade_costs[idx, 0] = distribution.upgrade_costs[technology] - data_handle.set_results(('distribution_upgrade_costs_' + - str(technology)), distribution_upgrade_costs) - - upgrade_cost_per_premises = ('upgrade_cost_per_premises_' + str(technology)) - upgrade_cost_per_premises = np.empty( - (self.system.number_of_assets['distributions'], 1)) - for idx, distribution in enumerate(self.system.assets['distributions']): - if distribution._clients: - upgrade_cost_per_premises[idx, 0] = \ - distribution.upgrade_costs[technology] / len(distribution._clients) - else: - upgrade_cost_per_premises[idx, 0] = 0 - data_handle.set_results(('premises_upgrade_costs_' + str(technology)), - upgrade_cost_per_premises) - - # premises passed - premises_passed = ('premises_passed_with_' + str(technology)) - premises_passed = np.empty((1, 1)) - premises_passed[0, 0] = sum(getattr(premise, technology) - for premise in self.system._premises) - print("* {} premises passed {}".format(technology, premises_passed)) - data_handle.set_results(('premises_passed_with_' + str(technology)), premises_passed) - - percentage_of_premises_passed = ('percentage_of_premises_passed_with_' + str(technology)) - percentage_of_premises_passed = np.empty((1, 1)) - percentage_of_premises_passed[0, 0] = round( - ( - sum(getattr(premise, technology) for premise in self.system._premises) - / len(self.system._premises) - * 100 - ), - 2) - print("* {} percentage of premises passed {}".format( - technology, percentage_of_premises_passed)) - data_handle.set_results( - 'percentage_of_premises_passed_with_' + str(technology), - percentage_of_premises_passed) - - # premises connected - premises_connected = ('premises_connected_with_' + str(technology)) - premises_connected = np.empty((1, 1)) - premises_connected[0, 0] = sum( - getattr(premise, technology) - for premise in self.system._premises - if premise.adoption_desirability - ) - print("* {} premises connected {}".format(technology, premises_connected)) - data_handle.set_results(('premises_connected_with_' + str(technology)), premises_connected) - - percentage_of_premises_connected = ( - 'percentage_of_premises_connected_with_' + str(technology)) - percentage_of_premises_connected = np.empty((1, 1)) - percentage_of_premises_connected[0, 0] = round( - ( - sum( - getattr(premise, technology) - for premise in self.system._premises - if premise.adoption_desirability - ) - / len(self.system._premises) - * 100 - ), - 2) - print("* {} percentage of premises connected {}".format( - technology, percentage_of_premises_connected)) - data_handle.set_results(('percentage_of_premises_connected_with_' + str(technology)), - percentage_of_premises_connected) - - # Regional output - lad_names = self.get_region_names('lad2016') - num_lads = len(lad_names) - num_fttp = np.zeros((num_lads, 1)) - num_fttdp = np.zeros((num_lads, 1)) - num_fttc = np.zeros((num_lads, 1)) - num_adsl = np.zeros((num_lads, 1)) - coverage = self.system.coverage() - for i, lad in enumerate(lad_names): - if lad not in coverage: - continue - stats = coverage[lad] - num_fttp[i, 0] = stats['num_fttp'] - num_fttdp[i, 0] = stats['num_fttdp'] - num_fttc[i, 0] = stats['num_fttc'] - num_adsl[i, 0] = stats['num_adsl'] - - data_handle.set_results('lad_premises_with_fttp', num_fttp) - data_handle.set_results('lad_premises_with_fttdp', num_fttdp) - - # get cambridge exchange data - if policy == 'fttp_rollout_per_distribution' and technology == 'fttp': - - path_main = os.path.dirname(os.path.abspath(__file__)) - config = configparser.ConfigParser() - config.read(os.path.join(path_main, 'wrapperconfig.ini')) - base_path = config['PATHS']['path_export_data'] - - def csv_writer(data, filename, fieldnames): - with open(os.path.join(base_path, filename), 'w') as csv_file: - writer = csv.DictWriter(csv_file, fieldnames, lineterminator='\n') - writer.writeheader() - writer.writerows(data) - - def write_out_upgrades(data): - export_data = [] - for datum in data: - export_data.append({ - 'id': datum.id, - 'upgrade': datum.fttp, - 'year': now - }) - return export_data - - # get exchanges - exchange = [ - exchange - for exchange in self.system._exchanges - if exchange.id == 'exchange_EACAM' - ][0] - - # get cabinets - cabinets = exchange._clients - cabinet_export_data = write_out_upgrades(cabinets) - - # get distributions - distributions = [] - for cabinet in cabinets: - distributions.extend(cabinet._clients) - distribution_export_data = write_out_upgrades(distributions) - - # get premises - premises = [] - for distribution in distributions: - premises.extend(distribution._clients) - - premises_export_data = [] - for premise in premises: - premises_export_data.append({ - 'id': premise.id, - 'adoption_desirability': premise.adoption_desirability, - 'premises_passed': premise.fttp, - 'year': now - }) - - # get exchange to cabinet links - exchange_to_cabinet_links = [ - link - for link in self.system._links_from_cabinets - if link.dest == 'exchange_EACAM' - ] - - # get cabinet to dist point links - cab_to_dist_point_links = exchange_to_cabinet_links.origin - - # get distributions - cab_to_dist_point_links = [] - for link in cab_to_dist_point_links: - cab_to_dist_point_links.extend(link.origin) - print(cab_to_dist_point_links) - - # set fieldnames - generic_fieldnames = ['id', 'upgrade', 'year'] - premises_fieldnames = ['id', 'adoption_desirability', 'premises_passed', 'year'] - - # write out - csv_writer( - cabinet_export_data, - 'cabinet_data{}.csv'.format(now), - generic_fieldnames) - csv_writer( - distribution_export_data, - 'distribution_data{}.csv'.format(now), - generic_fieldnames) - csv_writer( - premises_export_data, - 'premises_data{}.csv'.format(now), - premises_fieldnames) - - # ---- - # Exit - # ---- - self.logger.info("DigitalCommsWrapper produced outputs in %s", now) - - -def read_shapefile(file): - """Read properties for all features in a shapefile - """ - with fiona.open(file, 'r') as source: - return [f['properties'] for f in source] + aggregate_coverage = self.system.aggregate_coverage() + capacity = self.system.capacity() + spend = self.system.spend() + + data_handle.set_results('coverage', coverage) + data_handle.set_results('aggregate_coverage', aggregate_coverage) + data_handle.set_results('capacity', capacity) + data_handle.set_results('spend', spend) diff --git a/planning/digital_decisions.py b/planning/digital_decisions.py new file mode 100644 index 00000000..3171da62 --- /dev/null +++ b/planning/digital_decisions.py @@ -0,0 +1,80 @@ +from copy import copy + +from smif.decision.decision import RuleBased +from smif.data_layer.data_array import DataArray +from logging import getLogger +import pandas as pd + + +class DigitalDecisions(RuleBased): + + def __init__(self, timesteps, register): + super().__init__(timesteps, register) + self.model_name = 'digital_comms' + self.logger = getLogger(__name__) + + @staticmethod + def from_dict(config): + timesteps = config['timesteps'] + register = config['register'] + return DigitalDecisions(timesteps, register) + + def get_decision(self, data_handle): + + # Get the technology strategy parameter - this should consist of a string + # which describes the policy and + technology = 'fttdp' + policy = 'baseline' + + # ----------------------- + # Get scenario adoption rate + # ----------------------- + annual_adoption_rate = data_handle.get_data('adoption').data + + # get adoption desirability from previous timestep + adoption_desirability = [ + distribution for distribution in self.system._distributions + if distribution.adoption_desirability] + + total_distributions = [distribution for distribution in self.system._distributions] + + adoption_desirability_percentage = ( + len([dist.total_prems for dist in adoption_desirability]) / + len([dist.total_prems for dist in total_distributions]) * 100) + + percentage_annual_increase = round(float(annual_adoption_rate - \ + adoption_desirability_percentage), 1) + + # update the number of premises wanting to adopt (adoption_desirability) + distribution_adoption_desirability_ids = update_adoption_desirability( + self.system._distributions, percentage_annual_increase) + + # ----------------------- + # Run fixed network model + # ----------------------- + # get total adoption desirability for this time step (has to be done after + # system.update_adoption_desirability) + adoption_desirability_now = [ + dist for dist in self.system._distributions if dist.adoption_desirability] + + total_adoption_desirability_percentage = round( + (len([dist.total_prems for dist in adoption_desirability_now]) / + len([dist.total_prems for dist in total_distributions]) * 100), 2) + + # calculate the maximum adoption level based on the scenario, to make sure the + # model doesn't overestimate + adoption_cap = len(distribution_adoption_desirability_ids) + \ + sum(getattr(distribution, technology) for distribution in self.system._distributions) + + interventions = decide_interventions( + self.system, + now, + technology, + policy, + data_handle.get_parameter('annual_budget').data, + adoption_cap, + data_handle.get_parameter('subsidy').data, + data_handle.get_parameter('telco_match_funding').data, + data_handle.get_parameter('service_obligation_capacity').data, + ) + return interventions \ No newline at end of file From 6906c20c8ac7df151ab31de85364fa7c8696573c Mon Sep 17 00:00:00 2001 From: Will Usher Date: Thu, 21 Mar 2019 09:07:34 +0000 Subject: [PATCH 6/6] Added some notes and hard coded parameterisation to decision module --- models/digital_comms/run.py | 3 --- planning/digital_decisions.py | 31 ++++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/models/digital_comms/run.py b/models/digital_comms/run.py index 7a5260b7..ed28f700 100644 --- a/models/digital_comms/run.py +++ b/models/digital_comms/run.py @@ -4,13 +4,10 @@ import csv import os - import fiona # type: ignore import numpy as np # type: ignore from digital_comms.fixed_network.model import NetworkManager -from digital_comms.fixed_network.interventions import decide_interventions -from digital_comms.fixed_network.adoption import update_adoption_desirability from digital_comms.runner import read_csv, read_assets, read_links from smif.model.sector_model import SectorModel # type: ignore diff --git a/planning/digital_decisions.py b/planning/digital_decisions.py index 3171da62..dfe95451 100644 --- a/planning/digital_decisions.py +++ b/planning/digital_decisions.py @@ -4,6 +4,10 @@ from smif.data_layer.data_array import DataArray from logging import getLogger import pandas as pd +from typing import Dict, List + +from digital_comms.fixed_network.interventions import decide_interventions +from digital_comms.fixed_network.adoption import update_adoption_desirability class DigitalDecisions(RuleBased): @@ -19,7 +23,24 @@ def from_dict(config): register = config['register'] return DigitalDecisions(timesteps, register) - def get_decision(self, data_handle): + def get_decision(self, data_handle) -> List[Dict]: + """Return decisions for a given timestep and decision iteration + + Parameters + ---------- + results_handle : smif.data_layer.data_handle.ResultsHandle + + Returns + ------- + list of dict + + Examples + -------- + >>> register = {'intervention_a': {'capital_cost': {'value': 1234}}} + >>> dm = DecisionModule([2010, 2015], register) + >>> dm.get_decision(results_handle) + [{'name': 'intervention_a', 'build_year': 2010}]) + """ # Get the technology strategy parameter - this should consist of a string # which describes the policy and @@ -29,7 +50,11 @@ def get_decision(self, data_handle): # ----------------------- # Get scenario adoption rate # ----------------------- - annual_adoption_rate = data_handle.get_data('adoption').data + # annual_adoption_rate = data_handle.get_data('adoption').data + + distributions = data_handle.get_data('distributions') + + annual_adoption_rate = 40 # get adoption desirability from previous timestep adoption_desirability = [ @@ -68,7 +93,7 @@ def get_decision(self, data_handle): interventions = decide_interventions( self.system, - now, + data_handle.current_timestep, technology, policy, data_handle.get_parameter('annual_budget').data,