plan_gen.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/env python3
  2. ''' Python generator for MATSim plans. '''
  3. import sys
  4. import time
  5. import numpy as np
  6. import lxml.etree as etree
  7. # constants
  8. MIN_DEPARTURE_TIME = 8 * 3600 # '08:00:00'
  9. MAX_DEPARTURE_TIME = 9 * 3600 # '09:00:00'
  10. WORK_DURATION = '04:00:00'
  11. def read_nodes(input_network):
  12. ''' returns all network nodes as a list '''
  13. if not input_network:
  14. return None
  15. tree = etree.parse(input_network)
  16. return [node for node in tree.xpath("/network/nodes/node")]
  17. def rand_time(low, high):
  18. ''' returns a random time between low and high bounds (in seconds) '''
  19. delta = np.random.randint(high - low)
  20. return time.strftime('%H:%M:%S', time.gmtime(low + delta))
  21. def rand_node_xy(nodes, clusters):
  22. ''' returns a random node coordinates from a list of nodes '''
  23. used_nodes = nodes
  24. if any(clusters):
  25. cluster = np.random.randint(len(clusters))
  26. used_nodes = clusters[cluster]
  27. node = used_nodes[np.random.randint(len(used_nodes))]
  28. return (node.get('x'), node.get('y'))
  29. def rand_person(nodes, home_clusters, work_clusters):
  30. ''' returns a person as a dictionnary of random parameters '''
  31. home_xy = rand_node_xy(nodes, home_clusters)
  32. work_xy = rand_node_xy(nodes, work_clusters)
  33. home_departure = rand_time(MIN_DEPARTURE_TIME, MAX_DEPARTURE_TIME)
  34. return {'home': home_xy, 'work': work_xy, 'home_departure': home_departure}
  35. def create_child(parent_node, child_name, child_attrs=None):
  36. ''' creates an xml child element and set its attributes '''
  37. child = etree.SubElement(parent_node, child_name)
  38. if child_attrs is None:
  39. return child
  40. for attr, value in child_attrs.items():
  41. child.set(attr, value)
  42. return child
  43. def make_plans(persons):
  44. ''' makes xml tree of plans based on persons list '''
  45. plans = etree.Element('plans')
  46. for n, p in enumerate(persons):
  47. person = create_child(plans, 'person', {'id': str(n+1)})
  48. plan = create_child(person, 'plan')
  49. # plan
  50. create_child(plan, 'act', {'type': 'h', 'x': p['home'][0], 'y': p['home'][1], 'end_time': p['home_departure']})
  51. create_child(plan, 'leg', {'mode': 'car'})
  52. create_child(plan, 'act', {'type': 'w', 'x': p['work'][0], 'y': p['work'][1], 'dur': WORK_DURATION})
  53. create_child(plan, 'leg', {'mode': 'car'})
  54. create_child(plan, 'act', {'type': 'h', 'x': p['home'][0], 'y': p['home'][1]})
  55. return plans
  56. if __name__ == '__main__':
  57. # command line arguments
  58. if len(sys.argv) != 5:
  59. print('usage:', sys.argv[0], '<nb_persons> <input_network> <input_home_clusters> <input_work_clusters>')
  60. print('type "" if you don\'t want to use specific clusters')
  61. sys.exit(-1)
  62. NB_PERSONS = int(sys.argv[1])
  63. INPUT_NETWORK = sys.argv[2]
  64. INPUT_HOME_CLUSTERS = sys.argv[3].split(',')
  65. INPUT_WORK_CLUSTERS = sys.argv[4].split(',')
  66. # get data
  67. NODES = read_nodes(INPUT_NETWORK)
  68. HOME_CLUSTERS = [read_nodes(cluster) for cluster in INPUT_HOME_CLUSTERS]
  69. WORK_CLUSTERS = [read_nodes(cluster) for cluster in INPUT_WORK_CLUSTERS]
  70. # make xml
  71. PERSONS = [rand_person(NODES, HOME_CLUSTERS, WORK_CLUSTERS) for _ in range(NB_PERSONS)]
  72. PLANS = make_plans(PERSONS)
  73. # print XML
  74. print('<?xml version="1.0" ?>')
  75. print('<!DOCTYPE plans SYSTEM "http://www.matsim.org/files/dtd/plans_v4.dtd">')
  76. print(etree.tostring(PLANS, pretty_print=True).decode('utf-8'))