Einheit 4: Python-Grundlagen & erstes Modell
Vom ODD-Protokoll zum funktionierenden Code
Systemdefinition, Emergenz, Feedback, Weaver's Problemklassen, Cilliers' Merkmale.
Modellierungszyklus, vier Ansätze, ABM-Definition, Agenten als autonome Einheiten.
7 ODD-Elemente, Butterfly-Modell, Sugiyama-Staumodell als ODD beschrieben.
Tooling, Sprache, moderner Stil
Ctrl+`hello.pypython hello.py # system Python
uv run hello.py # with uv (recommended)
Im Zweifelsfall prüfen: welches Python?
which python
uvEin isolierter Ordner mit eigenem Python und eigenen Paketen. Jedes Projekt hat seine eigene Umgebung, so gibt es keine Konflikte zwischen Projekten.
uv ist ein moderner, schneller Ersatz für
pip, venv, conda und ähnliche Tools.
Ein einziges Werkzeug für alles.
# Create new project
uv init my-project
cd my-project
# Install packages
uv add numpy matplotlib
# Run script
uv run script.py
uv erstellt automatisch eine .venv und eine
uv.lock-Datei. Ihr müsst euch nicht selbst
um virtuelle Umgebungen kümmern.
pyproject.toml[project]
name = "traffic-jam"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"matplotlib>=3.10",
]
uv init erstellt diese Datei,
uv add trägt Pakete ein.
requires-python
legt fest, welche Version installierte Packages unterstützen müssenuv installiert und verwaltet Python selbst.
Wenn requires-python = ">=3.12" gesetzt ist und ihr
kein passendes Python habt, lädt uv es automatisch herunter.
.py-Dateien.py)uv run script.py liefert
immer dasselbe Ergebnisx = 10 # ✓ runs
y = x + 5 # ✓ runs
print(y) # ✓ output: 15
print(z) # ✗ NameError! Only HERE.
print("done") # never reached
Zeilen 1 bis 3 laufen erfolgreich. Der Fehler in Zeile 4 fällt erst auf, wenn Python dort ankommt.
uv run script.py, fertig{}, um Codeblöcke zu definieren.
Falsche Einrückung führt zu Fehlern.
| Typ | Beispiel |
|---|---|
int | x = 42 |
float | pi = 3.14 |
str | name = "Hallo" |
bool | aktiv = True |
list | zahlen = [1, 2, 3] |
name = "Sugiyama"
n_vehicles = 22
road_length = 230.0
is_jammed = False
# f-strings for text formatting
print(f"{n_vehicles} Fahrzeuge auf {road_length} m")
a = 230.0
b = 22
x = a / b
l = []
for i in range(b):
l.append(i * x)
road_length = 230.0
n_vehicles = 22
spacing = road_length / n_vehicles
positions = []
for i in range(n_vehicles):
positions.append(i * spacing)
speed = 25.0
if speed > 30.0:
print("Too fast!")
elif speed < 5.0:
print("Almost stopped")
else:
print("Normal flow")
# Ternary (compact if/else)
label = "fast" if speed > 30.0 else "ok"
# for loop
for i in range(5):
print(f"Step {i}")
# while loop
t = 0.0
while t < 10.0:
t += 0.1
quadrate = []
for x in range(10):
quadrate.append(x ** 2)
quadrate = [x ** 2 for x in range(10)]
# With condition:
gerade = [x for x in range(20)
if x % 2 == 0]
def optimal_velocity(headway: float, v_max=9.25, d_min=4.0, d_max=25.0) -> float:
"""Calculate desired velocity based on headway distance."""
if headway <= d_min:
return 0.0
elif headway >= d_max:
return v_max
else:
return v_max * (headway - d_min) / (d_max - d_min)
headway: float dokumentiert den erwarteten Typ,
wenn kein Defaultwert vorhanden ist.
Standardwerte wie v_max=9.25 machen
Aufrufe flexibel. Der Typ ist hier offensichtlich.
""") beschreiben, was die Funktion tut.
Das ist Pflicht in unseren Projekten.
class Dog:
"""A dog with a name and energy level."""
def __init__(self, name: str, energy=100):
self.name = name
self.energy = energy
def bark(self):
"""Bark and lose some energy."""
self.energy -= 10
print(f"{self.name}: Woof!")
rex = Dog("Rex")
rex.bark() # Rex: Woof!
print(rex.energy) # 90
luna = Dog("Luna", energy=50)
luna.bark() # Luna: Woof!
print(luna.energy) # 40
Jedes Objekt hat seinen eigenen Zustand.
rex und luna sind unabhängig.
@dataclassclass Vehicle:
def __init__(self,
position: float,
velocity: float) -> None:
self.position = position
self.velocity = velocity
from dataclasses import dataclass
@dataclass
class Vehicle:
position: float
velocity: float
@dataclass generiert __init__,
__repr__ und __eq__ automatisch.
Weniger Boilerplate, gleiche Funktionalität.
from dataclasses import dataclass
@dataclass
class Agent:
"""Base class for all agents."""
position: float
@dataclass
class Vehicle(Agent):
"""Vehicle agent with velocity."""
velocity: float = 0.0
car = Vehicle(position=10.5, velocity=8.0)
print(car.position) # 10.5 (inherited from Agent)
print(car.velocity) # 8.0
Vererbung braucht man selten in einfachen ABMs. Gut zu kennen, aber nicht übernutzen.
# Standard library
import math
from pathlib import Path
from dataclasses import dataclass
# External packages (uv add ...)
import numpy as np
import matplotlib.pyplot as plt
my-project/
├── main.py # entry point
├── model.py # model classes
└── pyproject.toml # project file (uv)
# in main.py:
from model import Vehicle, TrafficModel
uv add statt pip install verwenden,
damit Abhängigkeiten in pyproject.toml landen.
.format()@dataclass für Datenklassenpathlib.Path statt os.pathfrom module import *print()-Debugging statt Breakpointsx: int = 5Ziel: Code, den man in 6 Monaten noch versteht. Docstrings + klare Namen + sparsame Type Hints = selbstdokumentierender Code.
Das Sugiyama-Staumodell in Python
Wir nehmen das ODD aus Einheit 3 und übersetzen es Schritt für Schritt in funktionierenden Python-Code.
Wir bauen das Modell gemeinsam
Öffnet VS Code und erstellt ein neues Projekt mit
uv init traffic-jam.
Wir gehen den Code Schritt für Schritt durch.
| Parameter | Werte zum Testen |
|---|---|
n_vehicles | 10, 15, 22, 30 |
sensitivity | 1.0, 2.0, 3.0 |
noise | 0.0, 0.1, 0.5 |
0.0)?Versionskontrolle für reproduzierbare Forschung
modell_final.py
modell_final_v2.py
modell_final_v2_wirklich_final.py
modell_backup_alt.py
modell_NICHT_LOESCHEN.py
Wer kennt das nicht?
Ein Ordner, dessen Änderungsverlauf Git verfolgt. Existiert lokal auf eurem Rechner und remote auf GitHub.
Ein Snapshot aller Dateien zu einem Zeitpunkt. Jeder Commit hat eine Nachricht: Was wurde geändert und warum?
Ein paralleler Entwicklungsstrang.
main ist der Hauptbranch.
Für den Kurs reicht main.
git add, git commit, ...git push lädt eure Commits auf GitHub hoch# Create new repo
git init
# Stage changes
git add model.py
# Save snapshot
git commit -m "Initial traffic model"
# Upload to GitHub
git push
# Clone repo from GitHub
git clone https://github.com/user/repo.git
cd repo
# ... work ...
# Upload changes
git add .
git commit -m "Add OVM function"
git push
git add → git commit → git push.
Das ist 90% eurer Git-Nutzung im Kurs.
@dataclassuv, virtuelle UmgebungenEinheit 5: Wir vertiefen die Modellierung und lernen, wie man ABMs systematisch analysiert.