aadtkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aadtkit-0.1.0/CHANGELOG.md +22 -0
- aadtkit-0.1.0/CITATION.cff +20 -0
- aadtkit-0.1.0/LICENSE +21 -0
- aadtkit-0.1.0/MANIFEST.in +9 -0
- aadtkit-0.1.0/PKG-INFO +225 -0
- aadtkit-0.1.0/README.md +190 -0
- aadtkit-0.1.0/examples/quickstart.py +65 -0
- aadtkit-0.1.0/pyproject.toml +105 -0
- aadtkit-0.1.0/setup.cfg +4 -0
- aadtkit-0.1.0/src/aadtkit/__init__.py +134 -0
- aadtkit-0.1.0/src/aadtkit/__main__.py +7 -0
- aadtkit-0.1.0/src/aadtkit/_version.py +1 -0
- aadtkit-0.1.0/src/aadtkit/aadt.py +282 -0
- aadtkit-0.1.0/src/aadtkit/classification.py +105 -0
- aadtkit-0.1.0/src/aadtkit/cli.py +307 -0
- aadtkit-0.1.0/src/aadtkit/errors.py +17 -0
- aadtkit-0.1.0/src/aadtkit/expand.py +148 -0
- aadtkit-0.1.0/src/aadtkit/factors.py +372 -0
- aadtkit-0.1.0/src/aadtkit/io.py +312 -0
- aadtkit-0.1.0/src/aadtkit/peak.py +154 -0
- aadtkit-0.1.0/src/aadtkit/py.typed +0 -0
- aadtkit-0.1.0/src/aadtkit/quality.py +231 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/PKG-INFO +225 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/SOURCES.txt +33 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/dependency_links.txt +1 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/entry_points.txt +2 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/requires.txt +6 -0
- aadtkit-0.1.0/src/aadtkit.egg-info/top_level.txt +1 -0
- aadtkit-0.1.0/tests/conftest.py +41 -0
- aadtkit-0.1.0/tests/test_aadt.py +163 -0
- aadtkit-0.1.0/tests/test_expand.py +93 -0
- aadtkit-0.1.0/tests/test_factors.py +133 -0
- aadtkit-0.1.0/tests/test_io_cli.py +209 -0
- aadtkit-0.1.0/tests/test_peak_classes.py +103 -0
- aadtkit-0.1.0/tests/test_quality.py +71 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-11-09
|
|
8
|
+
### Added
|
|
9
|
+
- Continuous-count AADT: AASHTO method from monthly average days of week (MADW),
|
|
10
|
+
the FHWA hour-based calendar-weighted procedure (TMG 2022, 3.1.4.7) and the simple mean;
|
|
11
|
+
complete-day aggregation, monthly ADT, calendar day-of-week occurrences.
|
|
12
|
+
- Monthly, day-of-week and month x day-of-week expansion factors; factor groups with
|
|
13
|
+
per-factor standard deviation, CV and 95 % confidence half-width; k-means clustering of
|
|
14
|
+
stations on factor patterns.
|
|
15
|
+
- Short-count expansion to AADT with axle-correction and growth factors, on calendar days or
|
|
16
|
+
consecutive 24-hour blocks; axle-correction factors from classification counts.
|
|
17
|
+
- K-factor (n-th highest hour), D-factor, design hour volume and peak-hour factor.
|
|
18
|
+
- FHWA 13-class vehicle categories, class and group shares, truck share.
|
|
19
|
+
- Data-quality checks: missing hours, negative values, zero runs, constant runs, ceiling
|
|
20
|
+
and robust (median/MAD) outliers.
|
|
21
|
+
- CSV I/O for hourly counts and factor tables; `aadtkit` command line with `aadt`,
|
|
22
|
+
`factors`, `cluster`, `expand`, `peak`, `qc` and `classes`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
authors:
|
|
4
|
+
- family-names: "Eminoğlu"
|
|
5
|
+
given-names: "Yusuf"
|
|
6
|
+
email: "geospacephilo@gmail.com"
|
|
7
|
+
orcid: "https://orcid.org/0009-0005-6000-2934"
|
|
8
|
+
title: "aadtkit"
|
|
9
|
+
version: "0.1.0"
|
|
10
|
+
date-released: "2026-11-09"
|
|
11
|
+
license: "MIT"
|
|
12
|
+
repository-code: "https://gitlab.com/geophilo1/aadtkit_sdk"
|
|
13
|
+
url: "https://pypi.org/project/aadtkit/"
|
|
14
|
+
abstract: "Traffic count processing and AADT estimation following the FHWA Traffic Monitoring Guide: AASHTO and hour-based AADT for continuous count stations, monthly and day-of-week expansion factors, factor groups, short-count expansion with axle-correction factors, K-, D- and peak-hour factors, FHWA 13-class vehicle shares and data-quality checks."
|
|
15
|
+
keywords:
|
|
16
|
+
- traffic
|
|
17
|
+
- AADT
|
|
18
|
+
- traffic monitoring
|
|
19
|
+
- expansion factors
|
|
20
|
+
- transportation planning
|
aadtkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yusuf Eminoğlu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aadtkit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aadtkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Traffic count processing and AADT estimation following the FHWA Traffic Monitoring Guide: AASHTO and hour-based AADT, expansion factors, factor groups, short-count expansion, K/D/peak-hour factors, FHWA 13-class shares and data-quality checks.
|
|
5
|
+
Author-email: Yusuf Eminoğlu <geospacephilo@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/geophilo1/aadtkit_sdk
|
|
8
|
+
Project-URL: Repository, https://gitlab.com/geophilo1/aadtkit_sdk
|
|
9
|
+
Project-URL: Issues, https://gitlab.com/geophilo1/aadtkit_sdk/-/work_items
|
|
10
|
+
Project-URL: Changelog, https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: traffic,aadt,traffic-counts,traffic-monitoring,fhwa,expansion-factors,k-factor,transportation-planning,vehicle-classification,data-quality
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Environment :: Console
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
23
|
+
Classifier: Intended Audience :: Science/Research
|
|
24
|
+
Classifier: Intended Audience :: Developers
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# aadtkit
|
|
37
|
+
|
|
38
|
+
[](https://pypi.org/project/aadtkit/)
|
|
39
|
+
[](https://pypi.org/project/aadtkit/)
|
|
40
|
+
[](https://gitlab.com/geophilo1/aadtkit_sdk/-/pipelines)
|
|
41
|
+
[](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
**Traffic count processing and AADT estimation, following the FHWA *Traffic Monitoring Guide*.**
|
|
44
|
+
|
|
45
|
+
`aadtkit` turns hourly traffic counts into the numbers a traffic monitoring
|
|
46
|
+
program reports and a planner designs with:
|
|
47
|
+
|
|
48
|
+
- **AADT at continuous count stations**: the AASHTO method (averaging monthly
|
|
49
|
+
average days of week, MADW) and the hour-based, calendar-weighted
|
|
50
|
+
procedure FHWA has recommended since 2016 (TMG 2022);
|
|
51
|
+
- **expansion factors**: monthly, day-of-week and month x day-of-week;
|
|
52
|
+
- **factor groups**: group averages with dispersion and 95 % precision, and
|
|
53
|
+
k-means clustering of stations on their factor patterns;
|
|
54
|
+
- **short-count expansion** to AADT with axle-correction and growth factors;
|
|
55
|
+
- **design-hour characteristics**: K-factor (30th highest hour), D-factor,
|
|
56
|
+
design hour volume and peak-hour factor;
|
|
57
|
+
- **vehicle classification**: the FHWA 13 classes, class and group shares;
|
|
58
|
+
- **data-quality checks**: missing hours, zero runs, stuck counters, ceilings
|
|
59
|
+
and robust outliers;
|
|
60
|
+
- **CSV I/O** and an `aadtkit` command line.
|
|
61
|
+
|
|
62
|
+
It runs on the Python standard library alone.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install aadtkit
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Requires Python 3.9 or newer.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quickstart
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import aadtkit as ak
|
|
76
|
+
|
|
77
|
+
records = ak.read_hourly_csv("ccs_2024.csv") # station,datetime,volume[,direction][,vehicle_class]
|
|
78
|
+
series = ak.to_series(records, station="CCS-1") # {hour-start datetime: volume}
|
|
79
|
+
|
|
80
|
+
report = ak.check_hourly(series) # flag, never modify
|
|
81
|
+
clean = ak.drop_flagged(series, report)
|
|
82
|
+
|
|
83
|
+
res = ak.aadt_hourly_weighted(clean) # TMG 2022 hour-based procedure
|
|
84
|
+
res_aashto = ak.aadt_aashto(ak.daily_totals(clean)) # AASHTO / MADW
|
|
85
|
+
print(res.aadt, res.madt[7], res.madw[(7, 4)]) # AADT, July MADT, July Fridays
|
|
86
|
+
|
|
87
|
+
factors = ak.factors_from_result(res, "CCS-1") # AADT/MADT, AADT/ADT_dow, AADT/MADW
|
|
88
|
+
|
|
89
|
+
short = ak.to_series(ak.read_hourly_csv("short_count.csv"))
|
|
90
|
+
est = ak.short_count_aadt(short, factors, axle_factor=0.92, growth=ak.growth_factor(0.015, 1))
|
|
91
|
+
print(est.aadt, est.raw_adt)
|
|
92
|
+
|
|
93
|
+
k = ak.k_factor(clean, res.aadt) # 30th highest hour / AADT
|
|
94
|
+
d = ak.d_factor(ak.by_direction(records, "CCS-1")) # peak-direction share at that hour
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A complete runnable example on synthetic data is in
|
|
98
|
+
[`examples/quickstart.py`](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/examples/quickstart.py).
|
|
99
|
+
|
|
100
|
+
### Command line
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
aadtkit qc ccs.csv # issues as CSV, summary on stderr
|
|
104
|
+
aadtkit aadt ccs.csv --method hourly # or aashto / simple
|
|
105
|
+
aadtkit factors ccs.csv --group RURAL -o factors.csv
|
|
106
|
+
aadtkit cluster factors.csv -k 3 # factor groups by k-means
|
|
107
|
+
aadtkit expand short.csv --factors factors.csv --group RURAL --axle-factor 0.92
|
|
108
|
+
aadtkit peak ccs.csv --nth 30 # K- and D-factor
|
|
109
|
+
aadtkit classes class_counts.csv # FHWA 13-class shares
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Add `--hour-ending` when timestamps (or hours 1-24) mark the end of the hour.
|
|
113
|
+
|
|
114
|
+
### CSV layout
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
station,datetime,volume,direction,vehicle_class
|
|
118
|
+
CCS-1,2024-01-01 00:00,312,NB,2
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`datetime` may be replaced by `date` + `hour`; `direction` and
|
|
122
|
+
`vehicle_class` are optional. Empty or `NA` volumes are missing hours.
|
|
123
|
+
Factor tables use `name,type,month,dow,factor` with `type` in `monthly`,
|
|
124
|
+
`dow`, `month_dow`. Days of week are numbered 0 = Monday ... 6 = Sunday.
|
|
125
|
+
|
|
126
|
+
## API overview
|
|
127
|
+
|
|
128
|
+
| Area | Functions / classes |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| AADT | `daily_totals`, `aadt_aashto`, `aadt_hourly_weighted`, `aadt_simple`, `madt`, `dow_occurrences`, `AADTResult` |
|
|
131
|
+
| Factors | `factors_from_result`, `FactorSet.factor`, `group_factors`, `FactorGroup`, `FactorStats`, `cluster_stations`, `t_critical_95` |
|
|
132
|
+
| Axle correction | `axle_correction_factor`, `axle_correction_from_classes`, `DEFAULT_AXLES_PER_CLASS` |
|
|
133
|
+
| Short counts | `short_count_aadt`, `expand_volume`, `growth_factor`, `split_24h_blocks`, `ShortCountEstimate` |
|
|
134
|
+
| Design hour | `highest_hours`, `nth_highest_hour`, `k_factor`, `d_factor`, `design_hour_volume`, `peak_hour_factor` |
|
|
135
|
+
| Classification | `FHWAClass`, `CLASS_DESCRIPTIONS`, `class_shares`, `group_shares`, `truck_share` |
|
|
136
|
+
| Quality | `check_hourly`, `QualityReport`, `QualityIssue`, `drop_flagged` |
|
|
137
|
+
| I/O | `read_hourly_csv`, `write_hourly_csv`, `to_series`, `by_station`, `by_direction`, `class_totals`, `duplicate_keys`, `read_factors_csv`, `write_factors_csv` |
|
|
138
|
+
|
|
139
|
+
## Methods and sources
|
|
140
|
+
|
|
141
|
+
**AASHTO method** (TMG 2013, Section 3.2.1, Step 7; adopted by FHWA and the
|
|
142
|
+
AASHTO *Guidelines for Traffic Data Programs*):
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
AADT = 1/7 * sum_i [ 1/12 * sum_j ( 1/n_ij * sum_k VOL_ijk ) ]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`VOL_ijk` is the daily volume of the k-th occurrence of day of week *i* in
|
|
149
|
+
month *j*; the inner mean is the monthly average day of week (MADW). All 84
|
|
150
|
+
month x day-of-week cells need at least one complete day; `allow_missing_cells`
|
|
151
|
+
relaxes this explicitly.
|
|
152
|
+
|
|
153
|
+
**Hour-based procedure** (TMG 2022, Section 3.1.4.7, Step 3):
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
MADT_m = sum_j w_jm * sum_h (1/n_hjm * sum_i VOL_ihjm) / sum_j w_jm
|
|
157
|
+
AADT = sum_m d_m * MADT_m / sum_m d_m
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`w_jm` is the number of times day of week *j* occurs in month *m* (4 or 5) and
|
|
161
|
+
`d_m` the number of days in the month. Hour-level averaging lets partial days
|
|
162
|
+
contribute; with a complete year it equals the plain mean of all 365/366 days.
|
|
163
|
+
|
|
164
|
+
**Factors** (TMG 2022, 3.1.4.7, Steps 4-5): monthly factor `AADT / MADT_m`,
|
|
165
|
+
day-of-week factor `AADT / ADT_j`, month x day-of-week factor
|
|
166
|
+
`AADT / MADW_mj`; group factors are the mean over the group's stations, with
|
|
167
|
+
precision `t(0.975, n-1) * s / sqrt(n)` (TMG 2022, 3.1.4.5 and 3.2.6.2).
|
|
168
|
+
|
|
169
|
+
**Short counts**: `AADT = VOL_24 * M * D * A * G`, applied seasonality first
|
|
170
|
+
(TMG 2022, 3.2.8, worked example `518 x 0.95 x 1.24 = 610`, reproduced in the
|
|
171
|
+
tests). The axle-correction factor is vehicles per axle pair from a
|
|
172
|
+
classification count, `ACF = vehicles / (axles / 2)` (TMG glossary: vehicles
|
|
173
|
+
divided by axles; the divisor 2 reflects counters that register one count per
|
|
174
|
+
two axle hits and is a parameter).
|
|
175
|
+
|
|
176
|
+
**Design hour**: `K = V30 / AADT` with `V30` the 30th highest hourly volume
|
|
177
|
+
of the year (TMG 2022, 3.1.2 and 3.1.4.3; AASHTO *Green Book*);
|
|
178
|
+
`D` = peak-direction share of that hour; `PHF = V / (4 * V15)` (*Highway
|
|
179
|
+
Capacity Manual*).
|
|
180
|
+
|
|
181
|
+
**Classification**: FHWA 13-category scheme; default groups follow HPMS
|
|
182
|
+
(single-unit truck and bus = classes 4-7, combination truck = 8-13).
|
|
183
|
+
|
|
184
|
+
**Quality**: robust z-score `0.6745 |x - median| / MAD` within each
|
|
185
|
+
day-of-week x hour group (Iglewicz and Hoaglin, 1993).
|
|
186
|
+
|
|
187
|
+
References:
|
|
188
|
+
|
|
189
|
+
- FHWA (2022). *Traffic Monitoring Guide*. U.S. Department of Transportation,
|
|
190
|
+
Federal Highway Administration. <https://www.fhwa.dot.gov/policyinformation/tmguide/>
|
|
191
|
+
- FHWA (2013). *Traffic Monitoring Guide*, Chapter 3.
|
|
192
|
+
- AASHTO (2009). *AASHTO Guidelines for Traffic Data Programs*, 2nd ed.
|
|
193
|
+
- Transportation Research Board. *Highway Capacity Manual*.
|
|
194
|
+
- NCHRP Research Report 1081 (2024). *Guide on Methods for Assigning Counts to
|
|
195
|
+
Adjustment Factor Groups*. National Academies Press.
|
|
196
|
+
|
|
197
|
+
## Limitations
|
|
198
|
+
|
|
199
|
+
- Quality thresholds (zero run 6 h, constant run 4 h, z > 5) are engineering
|
|
200
|
+
defaults, not FHWA values; set them to your agency's validation rules.
|
|
201
|
+
- `DEFAULT_AXLES_PER_CLASS` uses nominal axle numbers; classes 3, 4, 7, 8, 10,
|
|
202
|
+
11 and 13 cover ranges. Use measured axles per class where available.
|
|
203
|
+
- k-means on factor vectors is one of several grouping approaches; groups
|
|
204
|
+
should still be reviewed against road function and geography, and short
|
|
205
|
+
count sites must be assigned to groups by the analyst.
|
|
206
|
+
- Incomplete days are never imputed. Daylight-saving shifts are not handled;
|
|
207
|
+
supply local standard time or UTC.
|
|
208
|
+
- Only 95 % confidence intervals are tabulated (t values for df <= 30, 40, 60,
|
|
209
|
+
120, interpolated otherwise).
|
|
210
|
+
|
|
211
|
+
## Academic citation
|
|
212
|
+
|
|
213
|
+
```bibtex
|
|
214
|
+
@software{eminoglu_aadtkit,
|
|
215
|
+
author = {Eminoğlu, Yusuf},
|
|
216
|
+
title = {aadtkit},
|
|
217
|
+
year = {2026},
|
|
218
|
+
version = {0.1.0},
|
|
219
|
+
url = {https://gitlab.com/geophilo1/aadtkit_sdk}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT, see [LICENSE](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/LICENSE). Contact: geospacephilo@gmail.com
|
aadtkit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# aadtkit
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/aadtkit/)
|
|
4
|
+
[](https://pypi.org/project/aadtkit/)
|
|
5
|
+
[](https://gitlab.com/geophilo1/aadtkit_sdk/-/pipelines)
|
|
6
|
+
[](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
**Traffic count processing and AADT estimation, following the FHWA *Traffic Monitoring Guide*.**
|
|
9
|
+
|
|
10
|
+
`aadtkit` turns hourly traffic counts into the numbers a traffic monitoring
|
|
11
|
+
program reports and a planner designs with:
|
|
12
|
+
|
|
13
|
+
- **AADT at continuous count stations**: the AASHTO method (averaging monthly
|
|
14
|
+
average days of week, MADW) and the hour-based, calendar-weighted
|
|
15
|
+
procedure FHWA has recommended since 2016 (TMG 2022);
|
|
16
|
+
- **expansion factors**: monthly, day-of-week and month x day-of-week;
|
|
17
|
+
- **factor groups**: group averages with dispersion and 95 % precision, and
|
|
18
|
+
k-means clustering of stations on their factor patterns;
|
|
19
|
+
- **short-count expansion** to AADT with axle-correction and growth factors;
|
|
20
|
+
- **design-hour characteristics**: K-factor (30th highest hour), D-factor,
|
|
21
|
+
design hour volume and peak-hour factor;
|
|
22
|
+
- **vehicle classification**: the FHWA 13 classes, class and group shares;
|
|
23
|
+
- **data-quality checks**: missing hours, zero runs, stuck counters, ceilings
|
|
24
|
+
and robust outliers;
|
|
25
|
+
- **CSV I/O** and an `aadtkit` command line.
|
|
26
|
+
|
|
27
|
+
It runs on the Python standard library alone.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install aadtkit
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Requires Python 3.9 or newer.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quickstart
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import aadtkit as ak
|
|
41
|
+
|
|
42
|
+
records = ak.read_hourly_csv("ccs_2024.csv") # station,datetime,volume[,direction][,vehicle_class]
|
|
43
|
+
series = ak.to_series(records, station="CCS-1") # {hour-start datetime: volume}
|
|
44
|
+
|
|
45
|
+
report = ak.check_hourly(series) # flag, never modify
|
|
46
|
+
clean = ak.drop_flagged(series, report)
|
|
47
|
+
|
|
48
|
+
res = ak.aadt_hourly_weighted(clean) # TMG 2022 hour-based procedure
|
|
49
|
+
res_aashto = ak.aadt_aashto(ak.daily_totals(clean)) # AASHTO / MADW
|
|
50
|
+
print(res.aadt, res.madt[7], res.madw[(7, 4)]) # AADT, July MADT, July Fridays
|
|
51
|
+
|
|
52
|
+
factors = ak.factors_from_result(res, "CCS-1") # AADT/MADT, AADT/ADT_dow, AADT/MADW
|
|
53
|
+
|
|
54
|
+
short = ak.to_series(ak.read_hourly_csv("short_count.csv"))
|
|
55
|
+
est = ak.short_count_aadt(short, factors, axle_factor=0.92, growth=ak.growth_factor(0.015, 1))
|
|
56
|
+
print(est.aadt, est.raw_adt)
|
|
57
|
+
|
|
58
|
+
k = ak.k_factor(clean, res.aadt) # 30th highest hour / AADT
|
|
59
|
+
d = ak.d_factor(ak.by_direction(records, "CCS-1")) # peak-direction share at that hour
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A complete runnable example on synthetic data is in
|
|
63
|
+
[`examples/quickstart.py`](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/examples/quickstart.py).
|
|
64
|
+
|
|
65
|
+
### Command line
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
aadtkit qc ccs.csv # issues as CSV, summary on stderr
|
|
69
|
+
aadtkit aadt ccs.csv --method hourly # or aashto / simple
|
|
70
|
+
aadtkit factors ccs.csv --group RURAL -o factors.csv
|
|
71
|
+
aadtkit cluster factors.csv -k 3 # factor groups by k-means
|
|
72
|
+
aadtkit expand short.csv --factors factors.csv --group RURAL --axle-factor 0.92
|
|
73
|
+
aadtkit peak ccs.csv --nth 30 # K- and D-factor
|
|
74
|
+
aadtkit classes class_counts.csv # FHWA 13-class shares
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Add `--hour-ending` when timestamps (or hours 1-24) mark the end of the hour.
|
|
78
|
+
|
|
79
|
+
### CSV layout
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
station,datetime,volume,direction,vehicle_class
|
|
83
|
+
CCS-1,2024-01-01 00:00,312,NB,2
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`datetime` may be replaced by `date` + `hour`; `direction` and
|
|
87
|
+
`vehicle_class` are optional. Empty or `NA` volumes are missing hours.
|
|
88
|
+
Factor tables use `name,type,month,dow,factor` with `type` in `monthly`,
|
|
89
|
+
`dow`, `month_dow`. Days of week are numbered 0 = Monday ... 6 = Sunday.
|
|
90
|
+
|
|
91
|
+
## API overview
|
|
92
|
+
|
|
93
|
+
| Area | Functions / classes |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| AADT | `daily_totals`, `aadt_aashto`, `aadt_hourly_weighted`, `aadt_simple`, `madt`, `dow_occurrences`, `AADTResult` |
|
|
96
|
+
| Factors | `factors_from_result`, `FactorSet.factor`, `group_factors`, `FactorGroup`, `FactorStats`, `cluster_stations`, `t_critical_95` |
|
|
97
|
+
| Axle correction | `axle_correction_factor`, `axle_correction_from_classes`, `DEFAULT_AXLES_PER_CLASS` |
|
|
98
|
+
| Short counts | `short_count_aadt`, `expand_volume`, `growth_factor`, `split_24h_blocks`, `ShortCountEstimate` |
|
|
99
|
+
| Design hour | `highest_hours`, `nth_highest_hour`, `k_factor`, `d_factor`, `design_hour_volume`, `peak_hour_factor` |
|
|
100
|
+
| Classification | `FHWAClass`, `CLASS_DESCRIPTIONS`, `class_shares`, `group_shares`, `truck_share` |
|
|
101
|
+
| Quality | `check_hourly`, `QualityReport`, `QualityIssue`, `drop_flagged` |
|
|
102
|
+
| I/O | `read_hourly_csv`, `write_hourly_csv`, `to_series`, `by_station`, `by_direction`, `class_totals`, `duplicate_keys`, `read_factors_csv`, `write_factors_csv` |
|
|
103
|
+
|
|
104
|
+
## Methods and sources
|
|
105
|
+
|
|
106
|
+
**AASHTO method** (TMG 2013, Section 3.2.1, Step 7; adopted by FHWA and the
|
|
107
|
+
AASHTO *Guidelines for Traffic Data Programs*):
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
AADT = 1/7 * sum_i [ 1/12 * sum_j ( 1/n_ij * sum_k VOL_ijk ) ]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`VOL_ijk` is the daily volume of the k-th occurrence of day of week *i* in
|
|
114
|
+
month *j*; the inner mean is the monthly average day of week (MADW). All 84
|
|
115
|
+
month x day-of-week cells need at least one complete day; `allow_missing_cells`
|
|
116
|
+
relaxes this explicitly.
|
|
117
|
+
|
|
118
|
+
**Hour-based procedure** (TMG 2022, Section 3.1.4.7, Step 3):
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
MADT_m = sum_j w_jm * sum_h (1/n_hjm * sum_i VOL_ihjm) / sum_j w_jm
|
|
122
|
+
AADT = sum_m d_m * MADT_m / sum_m d_m
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`w_jm` is the number of times day of week *j* occurs in month *m* (4 or 5) and
|
|
126
|
+
`d_m` the number of days in the month. Hour-level averaging lets partial days
|
|
127
|
+
contribute; with a complete year it equals the plain mean of all 365/366 days.
|
|
128
|
+
|
|
129
|
+
**Factors** (TMG 2022, 3.1.4.7, Steps 4-5): monthly factor `AADT / MADT_m`,
|
|
130
|
+
day-of-week factor `AADT / ADT_j`, month x day-of-week factor
|
|
131
|
+
`AADT / MADW_mj`; group factors are the mean over the group's stations, with
|
|
132
|
+
precision `t(0.975, n-1) * s / sqrt(n)` (TMG 2022, 3.1.4.5 and 3.2.6.2).
|
|
133
|
+
|
|
134
|
+
**Short counts**: `AADT = VOL_24 * M * D * A * G`, applied seasonality first
|
|
135
|
+
(TMG 2022, 3.2.8, worked example `518 x 0.95 x 1.24 = 610`, reproduced in the
|
|
136
|
+
tests). The axle-correction factor is vehicles per axle pair from a
|
|
137
|
+
classification count, `ACF = vehicles / (axles / 2)` (TMG glossary: vehicles
|
|
138
|
+
divided by axles; the divisor 2 reflects counters that register one count per
|
|
139
|
+
two axle hits and is a parameter).
|
|
140
|
+
|
|
141
|
+
**Design hour**: `K = V30 / AADT` with `V30` the 30th highest hourly volume
|
|
142
|
+
of the year (TMG 2022, 3.1.2 and 3.1.4.3; AASHTO *Green Book*);
|
|
143
|
+
`D` = peak-direction share of that hour; `PHF = V / (4 * V15)` (*Highway
|
|
144
|
+
Capacity Manual*).
|
|
145
|
+
|
|
146
|
+
**Classification**: FHWA 13-category scheme; default groups follow HPMS
|
|
147
|
+
(single-unit truck and bus = classes 4-7, combination truck = 8-13).
|
|
148
|
+
|
|
149
|
+
**Quality**: robust z-score `0.6745 |x - median| / MAD` within each
|
|
150
|
+
day-of-week x hour group (Iglewicz and Hoaglin, 1993).
|
|
151
|
+
|
|
152
|
+
References:
|
|
153
|
+
|
|
154
|
+
- FHWA (2022). *Traffic Monitoring Guide*. U.S. Department of Transportation,
|
|
155
|
+
Federal Highway Administration. <https://www.fhwa.dot.gov/policyinformation/tmguide/>
|
|
156
|
+
- FHWA (2013). *Traffic Monitoring Guide*, Chapter 3.
|
|
157
|
+
- AASHTO (2009). *AASHTO Guidelines for Traffic Data Programs*, 2nd ed.
|
|
158
|
+
- Transportation Research Board. *Highway Capacity Manual*.
|
|
159
|
+
- NCHRP Research Report 1081 (2024). *Guide on Methods for Assigning Counts to
|
|
160
|
+
Adjustment Factor Groups*. National Academies Press.
|
|
161
|
+
|
|
162
|
+
## Limitations
|
|
163
|
+
|
|
164
|
+
- Quality thresholds (zero run 6 h, constant run 4 h, z > 5) are engineering
|
|
165
|
+
defaults, not FHWA values; set them to your agency's validation rules.
|
|
166
|
+
- `DEFAULT_AXLES_PER_CLASS` uses nominal axle numbers; classes 3, 4, 7, 8, 10,
|
|
167
|
+
11 and 13 cover ranges. Use measured axles per class where available.
|
|
168
|
+
- k-means on factor vectors is one of several grouping approaches; groups
|
|
169
|
+
should still be reviewed against road function and geography, and short
|
|
170
|
+
count sites must be assigned to groups by the analyst.
|
|
171
|
+
- Incomplete days are never imputed. Daylight-saving shifts are not handled;
|
|
172
|
+
supply local standard time or UTC.
|
|
173
|
+
- Only 95 % confidence intervals are tabulated (t values for df <= 30, 40, 60,
|
|
174
|
+
120, interpolated otherwise).
|
|
175
|
+
|
|
176
|
+
## Academic citation
|
|
177
|
+
|
|
178
|
+
```bibtex
|
|
179
|
+
@software{eminoglu_aadtkit,
|
|
180
|
+
author = {Eminoğlu, Yusuf},
|
|
181
|
+
title = {aadtkit},
|
|
182
|
+
year = {2026},
|
|
183
|
+
version = {0.1.0},
|
|
184
|
+
url = {https://gitlab.com/geophilo1/aadtkit_sdk}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT, see [LICENSE](https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/LICENSE). Contact: geospacephilo@gmail.com
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""aadtkit quickstart on synthetic data (no files needed).
|
|
2
|
+
|
|
3
|
+
Run with: python examples/quickstart.py
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import datetime as dt
|
|
9
|
+
import math
|
|
10
|
+
import random
|
|
11
|
+
import tempfile
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import aadtkit as ak
|
|
15
|
+
|
|
16
|
+
# --- 1. A synthetic continuous count station (one year, two directions) ------
|
|
17
|
+
rng = random.Random(42)
|
|
18
|
+
season = {m: 1 + 0.2 * math.sin((m - 4) / 12 * 2 * math.pi) for m in range(1, 13)}
|
|
19
|
+
weekday = [1.0, 1.0, 1.02, 1.05, 1.15, 0.9, 0.8]
|
|
20
|
+
profile = [1, 1, 1, 1, 2, 4, 7, 9, 8, 5, 4, 4, 5, 5, 5, 6, 8, 9, 7, 5, 4, 3, 2, 2]
|
|
21
|
+
profile = [p / sum(profile) for p in profile]
|
|
22
|
+
|
|
23
|
+
records = []
|
|
24
|
+
day = dt.date(2024, 1, 1)
|
|
25
|
+
while day.year == 2024:
|
|
26
|
+
total = 12000 * season[day.month] * weekday[day.weekday()]
|
|
27
|
+
for h in range(24):
|
|
28
|
+
ts = dt.datetime.combine(day, dt.time(h))
|
|
29
|
+
vol = total * profile[h] * rng.uniform(0.95, 1.05)
|
|
30
|
+
nb_share = 0.6 if h < 12 else 0.4
|
|
31
|
+
records.append(ak.HourlyRecord("CCS-1", ts, round(vol * nb_share), "NB"))
|
|
32
|
+
records.append(ak.HourlyRecord("CCS-1", ts, round(vol * (1 - nb_share)), "SB"))
|
|
33
|
+
day += dt.timedelta(days=1)
|
|
34
|
+
|
|
35
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
36
|
+
path = Path(tmp) / "ccs.csv"
|
|
37
|
+
ak.write_hourly_csv(path, records)
|
|
38
|
+
records = ak.read_hourly_csv(path)
|
|
39
|
+
|
|
40
|
+
series = ak.to_series(records, station="CCS-1")
|
|
41
|
+
|
|
42
|
+
# --- 2. Quality checks -------------------------------------------------------
|
|
43
|
+
report = ak.check_hourly(series)
|
|
44
|
+
print(f"completeness {report.completeness:.1%}, issues: {len(report.issues)}")
|
|
45
|
+
|
|
46
|
+
# --- 3. AADT -----------------------------------------------------------------
|
|
47
|
+
hourly = ak.aadt_hourly_weighted(series)
|
|
48
|
+
aashto = ak.aadt_aashto(ak.daily_totals(series))
|
|
49
|
+
print(f"AADT (TMG 2022 hour-based) = {hourly.aadt:,.0f}")
|
|
50
|
+
print(f"AADT (AASHTO, MADW) = {aashto.aadt:,.0f}")
|
|
51
|
+
|
|
52
|
+
# --- 4. Factors and short-count expansion ------------------------------------
|
|
53
|
+
factors = ak.factors_from_result(hourly, "CCS-1")
|
|
54
|
+
print("monthly factors:", {m: round(f, 3) for m, f in factors.monthly.items()})
|
|
55
|
+
|
|
56
|
+
start = dt.datetime(2024, 4, 16, 9) # a 48-hour count starting Tuesday 09:00
|
|
57
|
+
short = {start + dt.timedelta(hours=i): series[start + dt.timedelta(hours=i)] for i in range(48)}
|
|
58
|
+
est = ak.short_count_aadt(short, factors, basis="blocks")
|
|
59
|
+
print(f"48-h count: raw ADT {est.raw_adt:,.0f} -> AADT estimate {est.aadt:,.0f}")
|
|
60
|
+
|
|
61
|
+
# --- 5. Design hour ----------------------------------------------------------
|
|
62
|
+
k = ak.k_factor(series, hourly.aadt)
|
|
63
|
+
d = ak.d_factor(ak.by_direction(records, "CCS-1"))
|
|
64
|
+
print(f"K30 = {k:.3f}, D = {d.d:.2f} ({d.peak_direction}), DHV = {hourly.aadt * k:,.0f}")
|
|
65
|
+
print("PHF of 15-min counts:", round(ak.peak_hour_factor([210, 245, 260, 230, 190]).phf, 3))
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aadtkit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Yusuf Eminoğlu", email = "geospacephilo@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
description = "Traffic count processing and AADT estimation following the FHWA Traffic Monitoring Guide: AASHTO and hour-based AADT, expansion factors, factor groups, short-count expansion, K/D/peak-hour factors, FHWA 13-class shares and data-quality checks."
|
|
12
|
+
keywords = [
|
|
13
|
+
"traffic",
|
|
14
|
+
"aadt",
|
|
15
|
+
"traffic-counts",
|
|
16
|
+
"traffic-monitoring",
|
|
17
|
+
"fhwa",
|
|
18
|
+
"expansion-factors",
|
|
19
|
+
"k-factor",
|
|
20
|
+
"transportation-planning",
|
|
21
|
+
"vehicle-classification",
|
|
22
|
+
"data-quality",
|
|
23
|
+
]
|
|
24
|
+
readme = "README.md"
|
|
25
|
+
license = "MIT"
|
|
26
|
+
license-files = ["LICENSE"]
|
|
27
|
+
requires-python = ">=3.9"
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 4 - Beta",
|
|
30
|
+
"Programming Language :: Python :: 3",
|
|
31
|
+
"Programming Language :: Python :: 3.9",
|
|
32
|
+
"Programming Language :: Python :: 3.10",
|
|
33
|
+
"Programming Language :: Python :: 3.11",
|
|
34
|
+
"Programming Language :: Python :: 3.12",
|
|
35
|
+
"Programming Language :: Python :: 3.13",
|
|
36
|
+
"Operating System :: OS Independent",
|
|
37
|
+
"Environment :: Console",
|
|
38
|
+
"Topic :: Scientific/Engineering",
|
|
39
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
40
|
+
"Intended Audience :: Science/Research",
|
|
41
|
+
"Intended Audience :: Developers",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
dependencies = []
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=7.0.0",
|
|
49
|
+
"pytest-cov>=4.0.0",
|
|
50
|
+
"ruff>=0.1.0",
|
|
51
|
+
"mypy>=1.0.0",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[project.scripts]
|
|
55
|
+
aadtkit = "aadtkit.cli:main"
|
|
56
|
+
|
|
57
|
+
[project.urls]
|
|
58
|
+
Homepage = "https://gitlab.com/geophilo1/aadtkit_sdk"
|
|
59
|
+
Repository = "https://gitlab.com/geophilo1/aadtkit_sdk"
|
|
60
|
+
Issues = "https://gitlab.com/geophilo1/aadtkit_sdk/-/work_items"
|
|
61
|
+
Changelog = "https://gitlab.com/geophilo1/aadtkit_sdk/-/blob/main/CHANGELOG.md"
|
|
62
|
+
|
|
63
|
+
[tool.setuptools]
|
|
64
|
+
package-dir = {"" = "src"}
|
|
65
|
+
|
|
66
|
+
[tool.setuptools.packages.find]
|
|
67
|
+
where = ["src"]
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.package-data]
|
|
70
|
+
aadtkit = ["py.typed"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 100
|
|
74
|
+
target-version = "py39"
|
|
75
|
+
exclude = [
|
|
76
|
+
"scratch",
|
|
77
|
+
".venv",
|
|
78
|
+
"build",
|
|
79
|
+
"dist",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint]
|
|
83
|
+
select = ["E", "F", "W", "I", "B", "C4"]
|
|
84
|
+
ignore = ["E501"]
|
|
85
|
+
|
|
86
|
+
[tool.mypy]
|
|
87
|
+
files = ["src"]
|
|
88
|
+
warn_unused_ignores = true
|
|
89
|
+
|
|
90
|
+
[tool.pytest.ini_options]
|
|
91
|
+
testpaths = ["tests"]
|
|
92
|
+
# Lets `pytest` run straight from a clone, without an editable install first.
|
|
93
|
+
pythonpath = ["src"]
|
|
94
|
+
filterwarnings = [
|
|
95
|
+
"ignore::DeprecationWarning",
|
|
96
|
+
"ignore::PendingDeprecationWarning",
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
[tool.coverage.run]
|
|
100
|
+
source = ["aadtkit"]
|
|
101
|
+
branch = true
|
|
102
|
+
|
|
103
|
+
[tool.coverage.report]
|
|
104
|
+
show_missing = true
|
|
105
|
+
fail_under = 85
|
aadtkit-0.1.0/setup.cfg
ADDED