from ..track import Track
from ..vehicle import Car
from .lap import lapsim
from .models import (
CompetitionData,
CompetitionResults,
CompetitionScoring,
EventResults,
)
from .utils import compute_efficiency_points, compute_event_points, energy_data
[docs]
class Competition:
"""
Runs and scores a full FSAE competition for a given car and set of tracks.
"""
def __init__(
self,
mycar: Car,
accel: Track,
skidpad: Track,
autoX: Track,
endurance: Track,
scoring: CompetitionScoring,
) -> None:
"""
Parameters
----------
mycar : Car
Vehicle to simulate through each event.
accel : Track
Acceleration event track.
skidpad : Track
Skidpad event track.
autoX : Track
Autocross event track.
endurance : Track
Endurance event track.
scoring : CompetitionScoring
Scoring configuration used to convert event times into points.
"""
self.mycar = mycar
self.accel = accel
self.skidpad = skidpad
self.autoX = autoX
self.endurance = endurance
self.scoring = scoring
[docs]
def to_data(self) -> CompetitionData:
"""
Serialize the Competition to a CompetitionData model for Pydantic serialization.
Returns
-------
CompetitionData
"""
return CompetitionData(
vehicle_model=self.mycar.params,
accel=self.accel.to_data(),
skidpad=self.skidpad.to_data(),
autoX=self.autoX.to_data(),
endurance=self.endurance.to_data(),
scoring=self.scoring,
)
[docs]
def accel_event(self, extract_internal_data: bool = False) -> EventResults:
"""
Simulates the acceleration event in the competition.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
Returns
-------
EventResults
The results of the acceleration event simulation.
"""
with self.mycar.aero.drs_disabled_override():
lapsim_results = lapsim(
mycar=self.mycar,
track=self.accel,
initial_velocity=0.5,
extract_internal_data=extract_internal_data,
)
tyour = lapsim_results.lap_t[-1]
points = compute_event_points(self.scoring.accel, tyour)
return EventResults(
points=points,
tyour=tyour,
lapsim_results=lapsim_results,
)
[docs]
def skidpad_event(self, extract_internal_data: bool = False) -> EventResults:
"""
Simulates the skidpad event in the competition.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
Returns
-------
EventResults
The results of the skidpad event simulation.
"""
lapsim_results = lapsim(
mycar=self.mycar,
track=self.skidpad,
multilap=False, # TODO: FIX THIS!
extract_internal_data=extract_internal_data,
)
tyour = lapsim_results.lap_t[-1]
points = compute_event_points(self.scoring.skidpad, tyour)
return EventResults(
points=points,
tyour=tyour,
lapsim_results=lapsim_results,
)
[docs]
def autoX_event(self, extract_internal_data: bool = False) -> EventResults:
"""
Simulates the autocross event in the competition.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
Returns
-------
EventResults
The results of the autocross event simulation.
Notes
-----
The initial velocity is set to 1.0 m/s rather than 0, since the
timer uses a transponder at the back of the car, giving roughly
one wheelbase of rollout before timing starts.
"""
lapsim_results = lapsim(
mycar=self.mycar,
track=self.autoX,
initial_velocity=1.0,
extract_internal_data=extract_internal_data,
)
tyour = lapsim_results.lap_t[-1]
points = compute_event_points(self.scoring.autoX, tyour)
return EventResults(
points=points,
tyour=tyour,
lapsim_results=lapsim_results,
)
[docs]
def endurance_event(
self, extract_internal_data: bool = False, use_coast: bool = True
) -> EventResults:
"""
Simulates the endurance event in the competition.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
use_coast : bool, optional
Whether to allow the car to coast and regen instead of braking, by
default True.
Returns
-------
EventResults
The results of the endurance event simulation.
Notes
-----
The initial velocity is set to 1.0 m/s for the same rollout reason
described in `autoX_event`.
"""
lapsim_results = lapsim(
mycar=self.mycar,
track=self.endurance,
multilap=False,
initial_velocity=1.0,
use_coast=use_coast,
extract_internal_data=extract_internal_data,
)
tyour = 22 * lapsim_results.lap_t[-1]
points = compute_event_points(self.scoring.endurance, tyour)
return EventResults(
points=points,
tyour=tyour,
lapsim_results=lapsim_results,
)
[docs]
def efficiency_endurance_event(
self, extract_internal_data: bool = False
) -> tuple[EventResults, float, float]:
"""
Simulates the endurance event in the competition, and also calculates efficiency points.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
Returns
-------
tuple[EventResults, float, float]
Endurance event results, efficiency points, and consumed energy in kWh.
"""
endu_res = self.endurance_event(extract_internal_data=extract_internal_data)
_, _, consumed_energy = energy_data(
endu_res.lapsim_results.lap_t, endu_res.lapsim_results.lap_powers
)
eff_points = compute_efficiency_points(
self.scoring.efficiency,
consumed_energy,
endu_res.tyour,
)
return endu_res, eff_points, consumed_energy * 22
[docs]
def run(
self,
extract_internal_data: bool = False,
) -> CompetitionResults:
"""
Runs all competition events and returns their results.
Parameters
----------
extract_internal_data : bool, optional
Whether to extract internal data during the simulation, by default False.
Returns
-------
CompetitionResults
Results from all competition events including efficiency points.
"""
accel_results = self.accel_event(extract_internal_data=extract_internal_data)
skidpad_results = self.skidpad_event(extract_internal_data=extract_internal_data)
autoX_results = self.autoX_event(extract_internal_data=extract_internal_data)
endurance_results, efficiency_points, consumed_energy = self.efficiency_endurance_event(
extract_internal_data=extract_internal_data
)
return CompetitionResults(
accel=accel_results,
skidpad=skidpad_results,
autoX=autoX_results,
endurance=endurance_results,
efficiency_points=efficiency_points,
endu_consumed_energy=consumed_energy,
)