|
| 1 | +import argparse |
| 2 | +import logging |
| 3 | +import os |
| 4 | +import json |
| 5 | +import pandas as pd |
| 6 | + |
| 7 | +import genet |
| 8 | +from genet import read_matsim |
| 9 | +from genet.utils.persistence import ensure_dir |
| 10 | +import genet.output.sanitiser as sanitiser |
| 11 | +from genet.output.geojson import save_geodataframe |
| 12 | +import genet.utils.elevation as elevation |
| 13 | + |
| 14 | +if __name__ == '__main__': |
| 15 | + arg_parser = argparse.ArgumentParser(description='Add elevation data to network nodes, validate it, and calculate link slopes.') |
| 16 | + |
| 17 | + arg_parser.add_argument('-n', |
| 18 | + '--network', |
| 19 | + help='Location of the input network.xml file', |
| 20 | + required=True) |
| 21 | + |
| 22 | + arg_parser.add_argument('-p', |
| 23 | + '--projection', |
| 24 | + help='The projection network is in, eg. "epsg:27700"', |
| 25 | + required=True) |
| 26 | + |
| 27 | + arg_parser.add_argument('-el', |
| 28 | + '--elevation', |
| 29 | + help='Path to the elevation tif file', |
| 30 | + required=True) |
| 31 | + |
| 32 | + arg_parser.add_argument('-nv', |
| 33 | + '--null_value', |
| 34 | + help='Value that represents null in the elevation tif file', |
| 35 | + required=True) |
| 36 | + |
| 37 | + arg_parser.add_argument('-od', |
| 38 | + '--output_dir', |
| 39 | + help='Output directory for the updated network', |
| 40 | + required=True) |
| 41 | + |
| 42 | + arg_parser.add_argument('-we', |
| 43 | + '--write_elevation_to_network', |
| 44 | + help='Whether node elevation data should be written as attribute to the network; defaults to True', |
| 45 | + default=True, |
| 46 | + type=bool) |
| 47 | + |
| 48 | + arg_parser.add_argument('-ws', |
| 49 | + '--write_slope_to_network', |
| 50 | + help='Whether link slope data should be written as attribute to the network; defaults to True', |
| 51 | + default=True, |
| 52 | + type=bool) |
| 53 | + |
| 54 | + arg_parser.add_argument('-sj', |
| 55 | + '--save_jsons', |
| 56 | + help='Whether elevation and slope dictionaries and report are saved; defaults to True', |
| 57 | + default=True, |
| 58 | + type=bool) |
| 59 | + |
| 60 | + args = vars(arg_parser.parse_args()) |
| 61 | + network = args['network'] |
| 62 | + projection = args['projection'] |
| 63 | + elevation = args['elevation'] |
| 64 | + tif_null_value = args['null_value'] |
| 65 | + output_dir = args['output_dir'] |
| 66 | + write_elevation_to_network = args['write_elevation_to_network'] |
| 67 | + write_slope_to_network = args['write_slope_to_network'] |
| 68 | + save_dict_to_json = args['save_jsons'] |
| 69 | + elevation_output_dir = os.path.join(output_dir, 'elevation') |
| 70 | + ensure_dir(elevation_output_dir) |
| 71 | + |
| 72 | + logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.WARNING) |
| 73 | + |
| 74 | + logging.info('Reading in network at {}'.format(network)) |
| 75 | + |
| 76 | + n = read_matsim( |
| 77 | + path_to_network=network, |
| 78 | + epsg=projection |
| 79 | + ) |
| 80 | + |
| 81 | + logging.info('Creating elevation dictionary for network nodes') |
| 82 | + elevation_dictionary = n.get_node_elevation_dictionary(elevation_tif_file_path=elevation, null_value=tif_null_value) |
| 83 | + |
| 84 | + if save_dict_to_json: |
| 85 | + with open(os.path.join(elevation_output_dir, 'node_elevation_dictionary.json'), 'w', |
| 86 | + encoding='utf-8') as f: |
| 87 | + json.dump(sanitiser.sanitise_dictionary(elevation_dictionary), f, ensure_ascii=False, indent=4) |
| 88 | + |
| 89 | + |
| 90 | + logging.info('Validating the node elevation data') |
| 91 | + report = genet.utils.elevation.validation_report_for_node_elevation(elevation_dictionary) |
| 92 | + logging.info(report['summary']) |
| 93 | + |
| 94 | + if save_dict_to_json: |
| 95 | + with open(os.path.join(elevation_output_dir, 'validation_report_for_elevation.json'), 'w', |
| 96 | + encoding='utf-8') as f: |
| 97 | + json.dump(sanitiser.sanitise_dictionary(report), f, ensure_ascii=False, indent=4) |
| 98 | + |
| 99 | + |
| 100 | + if write_elevation_to_network: |
| 101 | + logging.info('Adding node elevation as attribute to the network') |
| 102 | + node_attrib_dict = {} |
| 103 | + for node_id in elevation_dictionary.keys(): |
| 104 | + elevation_value = elevation_dictionary[node_id]['z'] |
| 105 | + node_attrib_dict[node_id] = {'z': elevation_value} |
| 106 | + n.apply_attributes_to_nodes(node_attrib_dict) |
| 107 | + |
| 108 | + gdf_nodes = n.to_geodataframe()['nodes'] |
| 109 | + gdf_nodes = gdf_nodes[['id', 'z', 'geometry']] |
| 110 | + save_geodataframe(gdf_nodes.to_crs('epsg:4326'), 'node_elevation', elevation_output_dir) |
| 111 | + |
| 112 | + |
| 113 | + logging.info('Creating slope dictionary for network links') |
| 114 | + slope_dictionary = n.get_link_slope_dictionary(elevation_dict=elevation_dictionary) |
| 115 | + |
| 116 | + if save_dict_to_json: |
| 117 | + with open(os.path.join(elevation_output_dir, 'link_slope_dictionary.json'), 'w', |
| 118 | + encoding='utf-8') as f: |
| 119 | + json.dump(sanitiser.sanitise_dictionary(slope_dictionary), f, ensure_ascii=False, indent=4) |
| 120 | + |
| 121 | + |
| 122 | + if write_slope_to_network: |
| 123 | + logging.info('Adding link slope as an additional attribute to the network') |
| 124 | + attrib_dict = {} |
| 125 | + for link_id in slope_dictionary.keys(): |
| 126 | + slope_value = slope_dictionary[link_id]['slope'] |
| 127 | + attrib_dict[link_id] = { |
| 128 | + 'attributes': {'slope': {'name': 'slope', 'class': 'java.lang.String', 'text': slope_value}}} |
| 129 | + n.apply_attributes_to_links(attrib_dict) |
| 130 | + |
| 131 | + gdf = n.to_geodataframe()['links'] |
| 132 | + df = pd.DataFrame(list(slope_dictionary.items()), columns = ['id','slope_tuple']) |
| 133 | + df['slope'] = [x['slope'] for x in df['slope_tuple']] |
| 134 | + df = df[['id', 'slope']] |
| 135 | + gdf_links = pd.merge(gdf, df, on='id') |
| 136 | + save_geodataframe(gdf_links.to_crs('epsg:4326'), 'link_slope', elevation_output_dir) |
| 137 | + |
| 138 | + |
| 139 | + logging.info('Writing the updated network') |
| 140 | + n.write_to_matsim(elevation_output_dir) |
0 commit comments