Skip to content

Commit

Permalink
Merge branch 'develop' into renata/528-add-support-to-more-than-one-t…
Browse files Browse the repository at this point in the history
…ransit-agency-in-gtfs-feeds
  • Loading branch information
r-akemii authored Oct 11, 2024
2 parents a5978c3 + e0adc70 commit eccc56e
Show file tree
Hide file tree
Showing 47 changed files with 664 additions and 733 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,14 @@ jobs:
- name: Test docstrings
run: |
python -m pytest --doctest-modules aequilibrae/log.py aequilibrae/parameters.py aequilibrae/paths/vdf.py
python -m pytest docs/source/modeling_with_aequilibrae/project_pieces --doctest-glob=*.rst
python -m pytest --doctest-modules aequilibrae/distribution --ignore=aequilibrae/distribution/setup_ipf.py
python -m pytest --doctest-modules aequilibrae/matrix
python -m pytest --doctest-modules aequilibrae/paths --ignore=aequilibrae/paths/setup_assignment.py
python -m pytest --doctest-modules aequilibrae/project
python -m pytest --doctest-modules aequilibrae/log.py aequilibrae/parameters.py
python -m pytest --doctest-modules aequilibrae/transit
python -m pytest --doctest-glob=*.rst docs/source/modeling_with_aequilibrae/project_pieces
python -m pytest --doctest-glob=*.rst docs/source/modeling_with_aequilibrae/static_traffic_assignment
- name: Build documentation
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,4 @@ coverage.xml

#### End snippet
.DS_Store
.vscode
36 changes: 15 additions & 21 deletions aequilibrae/distribution/gravity_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,32 @@ class GravityApplication:
"""Applies a synthetic gravity model.
Model is an instance of SyntheticGravityModel class.
Impedance is an instance of AequilibraEMatrix.
Row and Column vectors are instances of AequilibraeData.
.. code-block:: python
>>> import pandas as pd
>>> from aequilibrae import Project
>>> from aequilibrae.matrix import AequilibraeMatrix, AequilibraeData
>>> from aequilibrae.matrix import AequilibraeData
>>> from aequilibrae.distribution import SyntheticGravityModel, GravityApplication
>>> project = Project.from_path("/tmp/test_project_ga")
>>> project = create_example(project_path)
# We define the model we will use
>>> model = SyntheticGravityModel()
# Before adding a parameter to the model, you need to define the model functional form
>>> model.function = "GAMMA" # "EXPO" or "POWER"
# You can select one of GAMMA, EXPO or POWER.
>>> model.function = "GAMMA"
# Only the parameter(s) applicable to the chosen functional form will have any effect
>>> model.alpha = 0.1
>>> model.beta = 0.0001
# Or you can load the model from a file
# model.load('path/to/model/file')
# We load the impedance matrix
>>> matrix = AequilibraeMatrix()
>>> matrix.load('/tmp/test_project_ga/matrices/skims.omx')
>>> matrix.computational_view(['distance_blended'])
>>> matrix = project.matrices.get_matrix("skims")
>>> matrix.computational_view(["distance_blended"])
# We create the vectors we will use
>>> query = "SELECT zone_id, population, employment FROM zones;"
Expand All @@ -61,8 +58,11 @@ class GravityApplication:
>>> zones = df.index.shape[0]
# We create the vector database
>>> args = {"entries": zones, "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64], "memory_mode": True}
>>> args = {"entries": zones,
... "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64],
... "memory_mode": True}
>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)
Expand All @@ -81,20 +81,14 @@ class GravityApplication:
... "model": model,
... "columns": vectors,
... "column_field": "attractions",
... "output": '/tmp/test_project_ga/matrices/matrix.aem',
... "output": os.path.join(project_path, 'matrices/gravity_matrix.aem'),
... "nan_as_zero":True
... }
>>> gravity = GravityApplication(**args)
# Solve and save the outputs
>>> gravity.apply()
>>> gravity.output.export('/tmp/test_project_ga/matrices/omx_file.omx')
# To save your report into a file, you can do the following:
# with open('/tmp/test_project_ga/report.txt', 'w') as file:
# for line in gravity.report:
# file.write(f"{line}\\n")
>>> gravity.output.export(os.path.join(project_path, 'matrices/gravity_omx.omx'))
"""

def __init__(self, project=None, **kwargs):
Expand Down
32 changes: 11 additions & 21 deletions aequilibrae/distribution/gravity_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,32 @@
class GravityCalibration:
"""Calibrate a traditional gravity model
Available deterrence function forms are: 'EXPO' or 'POWER'. 'GAMMA'
Available deterrence function forms are: 'EXPO', 'POWER' or 'GAMMA'.
.. code-block:: python
>>> from aequilibrae import Project
>>> from aequilibrae.matrix import AequilibraeMatrix
>>> from aequilibrae.distribution import GravityCalibration
>>> project = Project.from_path("/tmp/test_project_gc")
>>> project = create_example(project_path)
# We load the impedance matrix
>>> matrix = AequilibraeMatrix()
>>> matrix.load('/tmp/test_project_gc/matrices/demand.omx')
>>> matrix.computational_view(['matrix'])
# We load the demand matrix
>>> demand = project.matrices.get_matrix("demand_omx")
>>> demand.computational_view()
# We load the impedance matrix
>>> impedmatrix = AequilibraeMatrix()
>>> impedmatrix.load('/tmp/test_project_gc/matrices/skims.omx')
>>> impedmatrix.computational_view(['time_final'])
# We load the skim matrix
>>> skim = project.matrices.get_matrix("skims")
>>> skim.computational_view(["time_final"])
# Creates the problem
>>> args = {"matrix": matrix,
... "impedance": impedmatrix,
>>> args = {"matrix": demand,
... "impedance": skim,
... "row_field": "productions",
... "function": 'expo',
... "nan_as_zero": True}
>>> gravity = GravityCalibration(**args)
# Solve and save outputs
>>> gravity.calibrate()
>>> gravity.model.save('/tmp/test_project_gc/dist_expo_model.mod')
# To save the model report in a file
# with open('/tmp/test_project_gc/report.txt', 'w') as f:
# for line in gravity.report:
# f.write(f'{line}\\n')
>>> gravity.model.save(os.path.join(project_path, 'dist_expo_model.mod'))
"""

def __init__(self, project=None, **kwargs):
Expand Down
34 changes: 17 additions & 17 deletions aequilibrae/distribution/ipf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,41 @@ class Ipf:
.. code-block:: python
>>> from aequilibrae import Project
>>> from aequilibrae.distribution import Ipf
>>> from aequilibrae.matrix import AequilibraeMatrix, AequilibraeData
>>> from aequilibrae.matrix import AequilibraeData
>>> project = Project.from_path("/tmp/test_project_ipf")
>>> project = create_example(project_path)
>>> matrix = AequilibraeMatrix()
# Here we can create from OMX or load from an AequilibraE matrix.
>>> matrix.load('/tmp/test_project/matrices/demand.omx')
>>> matrix = project.matrices.get_matrix("demand_omx")
>>> matrix.computational_view()
>>> args = {"entries": matrix.zones, "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64], "memory_mode": True}
>>> dataset_args = {"entries": matrix.zones,
... "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64],
... "memory_mode": True}
>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)
>>> vectors.create_empty(**dataset_args)
>>> vectors.productions[:] = matrix.rows()[:]
>>> vectors.attractions[:] = matrix.columns()[:]
# We assume that the indices would be sorted and that they would match the matrix indices
>>> vectors.index[:] = matrix.index[:]
>>> args = {
... "matrix": matrix, "rows": vectors, "row_field": "productions", "columns": vectors,
... "column_field": "attractions", "nan_as_zero": False}
>>> fratar = Ipf(**args)
>>> ipf_args = {"matrix": matrix,
... "rows": vectors,
... "row_field": "productions",
... "columns": vectors,
... "column_field": "attractions",
... "nan_as_zero": False}
>>> fratar = Ipf(**ipf_args)
>>> fratar.fit()
# We can get back to our OMX matrix in the end
>>> fratar.output.export("/tmp/to_omx_output.omx")
>>> fratar.output.export("/tmp/to_aem_output.aem")
>>> fratar.output.export(os.path.join(my_folder_path, "to_omx_output.omx"))
>>> fratar.output.export(os.path.join(my_folder_path, "to_omx_output.aem"))
"""

def __init__(self, project=None, **kwargs):
Expand Down
4 changes: 1 addition & 3 deletions aequilibrae/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ class Log:
.. code-block:: python
>>> from aequilibrae import Project
>>> project = Project()
>>> project.new(tmp_path_empty)
>>> project.new(project_path)
>>> log = project.log()
Expand Down
72 changes: 29 additions & 43 deletions aequilibrae/matrix/aequilibrae_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,30 @@


class AequilibraeData(object):
"""AequilibraE dataset"""
"""AequilibraE dataset
.. code-block:: python
>>> from aequilibrae.matrix import AequilibraeData
>>> args = {"file_path": os.path.join(my_folder_path, "vectors.aed"),
... "entries": 3,
... "field_names": ["production"],
... "data_types": [np.float64]}
>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)
>>> vectors.production[:] = [1, 4, 7]
>>> vectors.index[:] = [1, 2, 3]
>>> vectors.export(os.path.join(my_folder_path, "vectors.csv"))
>>> reload_dataset = AequilibraeData()
>>> reload_dataset.load(os.path.join(my_folder_path, "vectors.aed"))
>>> reload_dataset.production
memmap([1., 4., 7.])
"""

def __init__(self):
self.data = None
Expand All @@ -37,8 +60,8 @@ def create_empty(
Creates a new empty dataset
:Arguments:
**file_path** (:obj:`str`, *Optional*): Full path for the output data file. If *memory_mode* is 'false' and
path is missing, then the file is created in the temp folder
**file_path** (:obj:`str`, *Optional*): Full path for the output data file. If 'memory_mode' is ``False``
and path is missing, then the file is created in the temp folder
**entries** (:obj:`int`, *Optional*): Number of records in the dataset. Default is 1
Expand All @@ -51,27 +74,6 @@ def create_empty(
**memory_mode** (:obj:`bool`, *Optional*): If ``True``, dataset will be kept in memory.
If ``False``, the dataset will be a memory-mapped numpy array
.. code-block:: python
>>> from aequilibrae.matrix import AequilibraeData, AequilibraeMatrix
>>> mat = AequilibraeMatrix()
>>> mat.load('/tmp/test_project/matrices/demand.omx')
>>> mat.computational_view()
>>> vectors = "/tmp/test_project/vectors.aed"
>>> args = {
... "file_path": vectors,
... "entries": mat.zones,
... "field_names": ["origins", "destinations"],
... "data_types": [np.float64, np.float64]
... }
>>> dataset = AequilibraeData()
>>> dataset.create_empty(**args)
"""

if file_path is not None or memory_mode:
Expand Down Expand Up @@ -145,13 +147,6 @@ def load(self, file_path):
:Arguments:
**file_path** (:obj:`str`): Full file path to the AequilibraeData to be loaded
.. code-block:: python
>>> from aequilibrae.matrix import AequilibraeData
>>> dataset = AequilibraeData()
>>> dataset.load("/tmp/test_project/vectors.aed")
"""
f = open(file_path)
self.file_path = os.path.realpath(f.name)
Expand All @@ -173,14 +168,6 @@ def export(self, file_name, table_name="aequilibrae_table"):
**file_name** (:obj:`str`): File name with PATH and extension (csv, or sqlite3, sqlite or db)
**table_name** (:obj:`str`): It only applies if you are saving to an SQLite table. Otherwise ignored
.. code-block:: python
>>> from aequilibrae.matrix import AequilibraeData
>>> dataset = AequilibraeData()
>>> dataset.load("/tmp/test_project/vectors.aed")
>>> dataset.export("/tmp/test_project/vectors.csv")
"""

file_type = os.path.splitext(file_name)[1]
Expand Down Expand Up @@ -237,9 +224,8 @@ def random_name():
>>> from aequilibrae.matrix import AequilibraeData
>>> name = AequilibraeData().random_name() # doctest: +ELLIPSIS
# This is an example of output
# '/tmp/Aequilibrae_data_5werr5f36-b123-asdf-4587-adfglkjhqwe.aed'
>>> dataset = AequilibraeData()
>>> dataset.random_name() # doctest: +ELLIPSIS
'/tmp/Aequilibrae_data_...'
"""
return os.path.join(tempfile.gettempdir(), f"Aequilibrae_data_{uuid.uuid4()}.aed")
Loading

0 comments on commit eccc56e

Please sign in to comment.