ubc-solar-physics 1.0.5__cp312-cp312-macosx_11_0_arm64.whl → 1.7.3__cp312-cp312-macosx_11_0_arm64.whl

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.
Files changed (33) hide show
  1. physics/_version.py +2 -2
  2. physics/environment/__init__.py +0 -7
  3. physics/environment/gis/base_gis.py +14 -0
  4. physics/environment/gis/gis.py +37 -3
  5. physics/environment/gis/gis.rs +91 -3
  6. physics/environment/meteorology/clouded_meteorology.py +8 -9
  7. physics/environment/meteorology/irradiant_meteorology.py +11 -10
  8. physics/lib.rs +72 -6
  9. physics/models/battery/__init__.py +12 -1
  10. physics/models/battery/basic_battery.py +0 -1
  11. physics/models/battery/battery.rs +102 -0
  12. physics/models/battery/battery_config.py +107 -0
  13. physics/models/battery/battery_config.toml +6 -0
  14. physics/models/battery/battery_model.py +226 -0
  15. physics/models/battery/kalman_filter.py +223 -0
  16. physics/models/battery.rs +1 -1
  17. physics/models/motor/__init__.py +3 -1
  18. physics/models/motor/advanced_motor.py +196 -0
  19. physics/models/motor/base_motor.py +2 -0
  20. physics/models/motor/basic_motor.py +33 -14
  21. physics/models/regen/basic_regen.py +14 -1
  22. physics/models.rs +1 -1
  23. physics_rs/__init__.pyi +111 -0
  24. physics_rs.cpython-312-darwin.so +0 -0
  25. {ubc_solar_physics-1.0.5.dist-info → ubc_solar_physics-1.7.3.dist-info}/METADATA +12 -5
  26. ubc_solar_physics-1.7.3.dist-info/RECORD +57 -0
  27. {ubc_solar_physics-1.0.5.dist-info → ubc_solar_physics-1.7.3.dist-info}/WHEEL +1 -1
  28. ubc_solar_physics-1.7.3.dist-info/top_level.txt +2 -0
  29. core.cpython-312-darwin.so +0 -0
  30. physics/environment/race.py +0 -89
  31. ubc_solar_physics-1.0.5.dist-info/RECORD +0 -52
  32. ubc_solar_physics-1.0.5.dist-info/top_level.txt +0 -1
  33. {ubc_solar_physics-1.0.5.dist-info → ubc_solar_physics-1.7.3.dist-info}/LICENSE +0 -0
@@ -0,0 +1,196 @@
1
+ import numpy as np
2
+ from haversine import haversine, Unit
3
+ from numpy.typing import NDArray
4
+ from physics.models.motor import BasicMotor
5
+
6
+
7
+ class AdvancedMotor(BasicMotor):
8
+ def __init__(self, **kwargs):
9
+ super().__init__(**kwargs)
10
+ self.cornering_coefficient = 15 # tuned to Day 1 and 3 FSGP data
11
+
12
+ def calculate_energy_in(self, required_speed_kmh, gradients, wind_speeds, tick, coords):
13
+ """
14
+ A function which takes in array of elevation, array of wind speed, required
15
+ speed, returns the consumed energy.
16
+
17
+ :param np.ndarray required_speed_kmh: (float[N]) required speed array in km/h
18
+ :param np.ndarray gradients: (float[N]) gradient at parts of the road
19
+ :param np.ndarray wind_speeds: (float[N]) speeds of wind in m/s, where > 0 means against the direction of the vehicle
20
+ :param float tick: length of 1 update cycle in seconds
21
+ :param np.ndarray coords: ([float[N,2]) The lat,lon coordinate of the car at each tick
22
+ :returns: (float[N]) energy expended by the motor at every tick
23
+ :rtype: np.ndarray
24
+
25
+ """
26
+ net_force, required_angular_speed_rads = self.calculate_net_force(required_speed_kmh, wind_speeds, gradients)
27
+
28
+ cornering_work = self.calculate_cornering_losses(required_speed_kmh, coords, tick)
29
+
30
+ motor_output_energies = required_angular_speed_rads * net_force * self.tire_radius * tick + cornering_work
31
+ motor_output_energies = np.clip(motor_output_energies, a_min=0, a_max=None)
32
+
33
+ e_m = self.calculate_motor_efficiency(required_angular_speed_rads, motor_output_energies, tick)
34
+ e_mc = self.calculate_motor_controller_efficiency(required_angular_speed_rads, motor_output_energies, tick)
35
+
36
+ motor_controller_input_energies = motor_output_energies / (e_m * e_mc)
37
+
38
+ # Filter out and replace negative energy consumption as 0
39
+ motor_controller_input_energies = np.where(motor_controller_input_energies > 0,
40
+ motor_controller_input_energies, 0)
41
+
42
+ return motor_controller_input_energies
43
+
44
+ def calculate_cornering_losses(self, required_speed_kmh, coords, tick):
45
+ """
46
+ Calculate the energy losses due to cornering based on vehicle speed and trajectory.
47
+
48
+ :param np.ndarray required_speed_kmh: (float[N]) Required speed array in km/h
49
+ :param np.ndarray coords: (float[N, 2]) Array containing latitude and longitude coordinates of the car at each tick
50
+ :param float tick: Length of one update cycle in seconds
51
+ :returns: (float[N]) Energy loss due to cornering at each tick
52
+ :rtype: np.ndarray
53
+ """
54
+ required_speed_ms = required_speed_kmh / 3.6
55
+ cornering_radii = self.calculate_radii(coords)
56
+
57
+ centripetal_lateral_force = self.vehicle_mass * (required_speed_ms ** 2) / cornering_radii
58
+ centripetal_lateral_force = np.clip(centripetal_lateral_force, a_min=0, a_max=10000)
59
+
60
+ slip_angles_degrees = self.get_slip_angle_for_tire_force(centripetal_lateral_force)
61
+ slip_angles_radians = np.radians(slip_angles_degrees)
62
+ slip_distances = np.tan(slip_angles_radians) * required_speed_ms * tick
63
+
64
+ return slip_distances * centripetal_lateral_force * self.cornering_coefficient
65
+
66
+ def calculate_radii(self, coords):
67
+ """
68
+ Calculate the cornering radii for a given set of waypoints.
69
+
70
+ :param np.ndarray coords: (float[N, 2]) Array containing latitude and longitude coordinates of the car's path
71
+ :returns: (float[N]) Array of cornering radii at each waypoint
72
+ :rtype: np.ndarray
73
+ """
74
+
75
+ # pop off last coordinate if first and last coordinate are the same
76
+ repeated_last_coordinate = False
77
+ if np.array_equal(coords[0], coords[len(coords) - 1]):
78
+ coords = coords[:-1]
79
+ repeated_last_coordinate = True
80
+
81
+ cornering_radii = np.empty(len(coords))
82
+ for i in range(len(coords)):
83
+ # if the next point or previous point is out of bounds, wrap the index around the array
84
+ i2 = (i - 1) % len(coords)
85
+ i3 = (i + 1) % len(coords)
86
+ current_point = coords[i]
87
+ previous_point = coords[i2]
88
+ next_point = coords[i3]
89
+
90
+ x1 = 0
91
+ y1 = 0
92
+ x2, y2 = self.calculate_meter_distance(current_point, previous_point)
93
+ x3, y3 = self.calculate_meter_distance(current_point, next_point)
94
+ cornering_radii[i] = self.radius_of_curvature(x1, y1, x2, y2, x3, y3)
95
+
96
+ # If the last coordinate was removed, duplicate the first radius value to the end of the array
97
+ if repeated_last_coordinate:
98
+ cornering_radii = np.append(cornering_radii, cornering_radii[0])
99
+
100
+ # ensure that super large radii are bounded by a large number, like 10000
101
+ cornering_radii = np.where(np.isnan(cornering_radii), 10000, cornering_radii)
102
+ cornering_radii = np.where(cornering_radii > 10000, 10000, cornering_radii)
103
+
104
+ return cornering_radii
105
+
106
+ def generate_slip_angle_lookup(self, min_degrees, max_degrees, num_elements):
107
+ """
108
+ Generate a lookup table of slip angles and corresponding tire forces using Pacejka's Magic Formula.
109
+
110
+ https://www.edy.es/dev/docs/pacejka-94-parameters-explained-a-comprehensive-guide/
111
+
112
+ :param float min_degrees: Minimum slip angle in degrees
113
+ :param float max_degrees: Maximum slip angle in degrees
114
+ :param int num_elements: Number of discrete elements in the lookup table
115
+ :returns: (float[num_elements], float[num_elements]) Arrays of slip angles (degrees) and corresponding tire forces (Newtons)
116
+ :rtype: tuple[np.ndarray, np.ndarray]
117
+ """
118
+
119
+ b = .25 # Stiffness
120
+ c = 2.2 # Shape
121
+ d = 2.75 # Peak
122
+ e = 1.0 # Curvature
123
+
124
+ fz = self.vehicle_mass * 9.81 # Newtons
125
+
126
+ slip_angles = np.linspace(min_degrees, max_degrees, num_elements)
127
+ tire_forces = fz * d * np.sin(
128
+ c * np.arctan(b * slip_angles - e * (b * slip_angles - np.arctan(b * slip_angles))))
129
+
130
+ return slip_angles, tire_forces
131
+
132
+ def get_slip_angle_for_tire_force(self, desired_tire_force):
133
+ slip_angles, tire_forces = self.generate_slip_angle_lookup(0, 70, 100000)
134
+
135
+ # Use the numpy interpolation function to find slip angle for the given tire force
136
+ estimated_slip_angle = np.interp(desired_tire_force, tire_forces, slip_angles)
137
+
138
+ return estimated_slip_angle
139
+
140
+ @staticmethod
141
+ def calculate_meter_distance(coord1: NDArray, coord2: NDArray):
142
+ """
143
+ Calculate the x and y distance in meters between two latitude-longitude coordinates.
144
+
145
+ :param tuple coord1: (float[2]) The (latitude, longitude) coordinates of the first point
146
+ :param tuple coord2: (float[2]) The (latitude, longitude) coordinates of the second point
147
+ :returns: (float[2]) The x (longitude) and y (latitude) distances in meters
148
+ :rtype: tuple
149
+ """
150
+ lat1, lon1 = coord1
151
+ lat2, lon2 = coord2
152
+
153
+ # Base coordinate
154
+ coord_base = (lat1, lon1)
155
+ # Coordinate for latitude difference (keep longitude the same)
156
+ coord_lat = (lat2, lon1)
157
+ # Coordinate for longitude difference (keep latitude the same)
158
+ coord_long = (lat1, lon2)
159
+
160
+ # Calculate y distance (latitude difference)
161
+ y_distance = haversine(coord_base, coord_lat, unit=Unit.METERS)
162
+ # Calculate x distance (longitude difference)
163
+ x_distance = haversine(coord_base, coord_long, unit=Unit.METERS)
164
+
165
+ if lat2 < lat1:
166
+ y_distance = -y_distance
167
+ if lon2 < lon1:
168
+ x_distance = -x_distance
169
+
170
+ return x_distance, y_distance
171
+
172
+ @staticmethod
173
+ def radius_of_curvature(x1, y1, x2, y2, x3, y3):
174
+ """
175
+ Uses the circumcircle the radius of curvature of a circle passing through three points.
176
+
177
+ :param float x1: X-coordinate of the first point
178
+ :param float y1: Y-coordinate of the first point
179
+ :param float x2: X-coordinate of the second point
180
+ :param float y2: Y-coordinate of the second point
181
+ :param float x3: X-coordinate of the third point
182
+ :param float y3: Y-coordinate of the third point
183
+ :returns: Radius of curvature of the circle passing through the three points
184
+ :rtype: float
185
+ """
186
+ numerator = np.sqrt(
187
+ ((x3 - x2) ** 2 + (y3 - y2) ** 2) *
188
+ ((x1 - x3) ** 2 + (y1 - y3) ** 2) *
189
+ ((x2 - x1) ** 2 + (y2 - y1) ** 2)
190
+ )
191
+
192
+ denominator = 2 * abs(
193
+ ((x2 - x1) * (y1 - y3) - (x1 - x3) * (y2 - y1))
194
+ )
195
+
196
+ return numerator / denominator
@@ -4,3 +4,5 @@ from abc import ABC
4
4
  class BaseMotor(ABC):
5
5
  def __init__(self):
6
6
  super().__init__()
7
+
8
+
@@ -1,6 +1,6 @@
1
1
  import math
2
2
  import numpy as np
3
-
3
+ from numpy.typing import NDArray
4
4
  from physics.models.motor.base_motor import BaseMotor
5
5
  from physics.models.constants import ACCELERATION_G, AIR_DENSITY
6
6
 
@@ -33,7 +33,7 @@ class BasicMotor(BaseMotor):
33
33
  # print("torque experienced by motor: {} Nm".format(self.constant_torque))
34
34
 
35
35
  @staticmethod
36
- def calculate_motor_efficiency(motor_angular_speed, motor_output_energy, tick):
36
+ def calculate_motor_efficiency(motor_angular_speed, motor_output_energy, tick, *args, **kwargs):
37
37
  """
38
38
 
39
39
  Calculates a NumPy array of motor efficiency from NumPy array of operating angular speeds and NumPy array
@@ -98,19 +98,20 @@ class BasicMotor(BaseMotor):
98
98
 
99
99
  return e_mc
100
100
 
101
- def calculate_energy_in(self, required_speed_kmh, gradients, wind_speeds, tick):
101
+ def calculate_net_force(self,
102
+ required_speed_kmh: NDArray,
103
+ wind_speeds: NDArray,
104
+ gradients: NDArray
105
+ ) -> tuple[NDArray, NDArray]:
102
106
  """
103
-
104
- Create a function which takes in array of elevation, array of wind speed, required
105
- speed, returns the consumed energy.
106
-
107
- :param np.ndarray required_speed_kmh: (float[N]) required speed array in km/h
108
- :param np.ndarray gradients: (float[N]) gradient at parts of the road
109
- :param np.ndarray wind_speeds: (float[N]) speeds of wind in m/s, where > 0 means against the direction of the vehicle
110
- :param float tick: length of 1 update cycle in seconds
111
- :returns: (float[N]) energy expended by the motor at every tick
112
- :rtype: np.ndarray
113
-
107
+ Calculate the net force on the car, and the required wheel angular velocity.
108
+ Currently, considers:
109
+ 1. Rolling resistance of the wheels on the road
110
+ 2. Drag force (wind + forward velocity)
111
+ 3. Acceleration force (a = F / m)
112
+ 4. Gravitational force (force to go uphill)
113
+
114
+ :return: net force in N, wheel angular velocity in rad/s
114
115
  """
115
116
  required_speed_ms = required_speed_kmh / 3.6
116
117
 
@@ -129,6 +130,24 @@ class BasicMotor(BaseMotor):
129
130
 
130
131
  net_force = road_friction_array + drag_forces + g_forces + acceleration_force
131
132
 
133
+ return net_force, required_angular_speed_rads
134
+
135
+ def calculate_energy_in(self, required_speed_kmh, gradients, wind_speeds, tick, **kwargs):
136
+ """
137
+
138
+ Create a function which takes in array of elevation, array of wind speed, required
139
+ speed, returns the consumed energy.
140
+
141
+ :param np.ndarray required_speed_kmh: (float[N]) required speed array in km/h
142
+ :param np.ndarray gradients: (float[N]) gradient at parts of the road
143
+ :param np.ndarray wind_speeds: (float[N]) speeds of wind in m/s, where > 0 means against the direction of the vehicle
144
+ :param float tick: length of 1 update cycle in seconds
145
+ :returns: (float[N]) energy expended by the motor at every tick
146
+ :rtype: np.ndarray
147
+
148
+ """
149
+ net_force, required_angular_speed_rads = self.calculate_net_force(required_speed_kmh, wind_speeds, gradients)
150
+
132
151
  motor_output_energies = required_angular_speed_rads * net_force * self.tire_radius * tick
133
152
  motor_output_energies = np.clip(motor_output_energies, a_min=0, a_max=None)
134
153
 
@@ -12,6 +12,18 @@ class BasicRegen(BaseRegen):
12
12
  self.vehicle_mass = vehicle_mass
13
13
  self.kmh_to_mps = 0.278
14
14
 
15
+ def get_regen_efficiency(self, speed_array):
16
+ """
17
+ Returns a numpy array of regen efficiency percentage based on the vehicle speed in m/s.
18
+
19
+ :param speed_array: a numpy array of speeds in m/s
20
+ :returns: numpy array of regen efficiency percentage
21
+ """
22
+ # Efficiency polynomial, more details can be found in regen_analysis folder located in data_analysis
23
+ efficiency_poly = [0.022288416685942, 0.026545396753597]
24
+
25
+ return np.polyval(efficiency_poly, speed_array)
26
+
15
27
  def calculate_produced_energy(self, speed_kmh, gis_route_elevations, min_regen_speed, max_power):
16
28
  """
17
29
  Returns a numpy array containing the energy produced by regen
@@ -29,7 +41,8 @@ class BasicRegen(BaseRegen):
29
41
 
30
42
  # create regen energy produced array
31
43
  # if delta_energy is negative, we regen that energy back at the set efficiency rate; else 0 energy regen
32
- produced_energy = np.where(delta_energy < 0, abs(delta_energy) * self.EFFICIENCY, 0)
44
+ efficiencies = self.get_regen_efficiency(speed_ms)
45
+ produced_energy = np.where(delta_energy < 0, abs(delta_energy) * efficiencies, 0)
33
46
 
34
47
  # Regen does not occur below a certain speed
35
48
  produced_energy = np.where(speed_ms >= min_regen_speed, produced_energy, 0)
physics/models.rs CHANGED
@@ -1,5 +1,5 @@
1
1
  mod arrays;
2
- mod battery;
2
+ pub mod battery;
3
3
  mod lvs;
4
4
  mod motor;
5
5
  mod regen;
@@ -0,0 +1,111 @@
1
+ import numpy as np
2
+
3
+
4
+ def constrain_speeds(speed_limits: np.ndarray, speeds: np.ndarray, tick: int) -> np.ndarray:
5
+ """
6
+ Constrains the vehicle speeds based on the speed limits and computes new speeds.
7
+
8
+ :param speed_limits: Array of speed limits (km/h) for each point.
9
+ :param speeds: Array of vehicle speeds (km/h).
10
+ :param tick: The time step (in some unit, e.g., seconds or ticks).
11
+
12
+ :return: A NumPy array of constrained vehicle speeds (km/h).
13
+ """
14
+ ...
15
+
16
+
17
+ def calculate_array_ghi_times(python_local_times: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
18
+ """
19
+ Calculates the array of GHI times based on local times.
20
+
21
+ :param python_local_times: Array of local times (UNIX timestamps or other format).
22
+
23
+ :return: A tuple of two NumPy arrays:
24
+ - Day of year (f64)
25
+ - Local time (f64)
26
+ """
27
+ ...
28
+
29
+
30
+ def closest_gis_indices_loop(python_cumulative_distances: np.ndarray,
31
+ python_average_distances: np.ndarray) -> np.ndarray:
32
+ """
33
+ Finds the closest GIS indices based on cumulative and average distances.
34
+
35
+ :param python_cumulative_distances: Array of cumulative distances.
36
+ :param python_average_distances: Array of average distances.
37
+
38
+ :return: A NumPy array of indices (i64) corresponding to the closest GIS indices.
39
+ """
40
+ ...
41
+
42
+
43
+ def closest_weather_indices_loop(
44
+ python_cumulative_distances: np.ndarray,
45
+ python_average_distances: np.ndarray
46
+ ) -> np.ndarray:
47
+ """
48
+ Finds the closest weather indices based on cumulative and average distances.
49
+
50
+ :param python_cumulative_distances: Array of cumulative distances.
51
+ :param python_average_distances: Array of average distances.
52
+
53
+ :return: A NumPy array of indices (i64) corresponding to the closest weather indices.
54
+ """
55
+ ...
56
+
57
+
58
+ def weather_in_time(
59
+ python_unix_timestamps: np.ndarray,
60
+ python_indices: np.ndarray,
61
+ python_weather_forecast: np.ndarray,
62
+ index: int
63
+ ) -> np.ndarray:
64
+ """
65
+ Retrieves the weather forecast at specific times for given indices.
66
+
67
+ :param python_unix_timestamps: Array of UNIX timestamps.
68
+ :param python_indices: Array of indices to look up.
69
+ :param python_weather_forecast: Array of weather forecasts.
70
+ :param index: A specific index to look up in the weather forecast.
71
+
72
+ :return: A NumPy array of weather values (f64) at the specified times and indices.
73
+ """
74
+ ...
75
+
76
+
77
+ def update_battery_state(
78
+ python_energy_or_current_array: np.ndarray,
79
+ time_step: float,
80
+ initial_state_of_charge: float,
81
+ initial_polarization_potential: float,
82
+ python_internal_resistance_lookup: np.ndarray,
83
+ python_open_circuit_voltage_lookup: np.ndarray,
84
+ python_polarization_resistance_lookup: np.ndarray,
85
+ python_polarization_capacitance_lookup: np.ndarray,
86
+ nominal_charge_capacity: float,
87
+ is_power: bool,
88
+ quantization_step: float,
89
+ min_soc: float
90
+ ) -> tuple[np.ndarray, np.ndarray]:
91
+ """
92
+ Updates the battery state (SOC and terminal voltage) based on energy/current input.
93
+
94
+ :param python_energy_or_current_array: Array of energy or current input values (f64).
95
+ :param time_step: Time step (f64).
96
+ :param initial_state_of_charge: Initial state of charge (f64).
97
+ :param initial_polarization_potential: Initial polarization potential (f64).
98
+ :param python_internal_resistance_lookup: Array of internal resistance values (f64).
99
+ :param python_open_circuit_voltage_lookup: Array of open-circuit voltage values (f64).
100
+ :param python_polarization_resistance_lookup: Array of polarization resistance values (f64).
101
+ :param python_polarization_capacitance_lookup: Array of polarization capacitance values (f64).
102
+ :param nominal_charge_capacity: Nominal charge capacity (f64).
103
+ :param is_power: Boolean flag to indicate if the input is power (`True`) or current (`False`).
104
+ :param quantization_step: The step size used to quantize the SOC (f64).
105
+ :param min_soc: The minimum SOC used when computing the lookup tables
106
+
107
+ :return: A tuple containing:
108
+ - An array of updated SOC values (f64).
109
+ - An array of updated terminal voltage values (f64).
110
+ """
111
+ ...
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ubc-solar-physics
3
- Version: 1.0.5
3
+ Version: 1.7.3
4
4
  Summary: UBC Solar's Simulation Environment
5
5
  Author: Fisher Xue, Mihir Nimgade, Chris Chang, David Widjaja, Justin Hua, Ilya Veksler, Renu Rajamagesh, Ritchie Xia, Erik Langille, Chris Aung, Nicolas Ric, Ishaan Trivedi, Jason Liang, Felix Toft, Mack Wilson, Jonah Lee, Tamzeed Quazi, Joshua Riefman
6
6
  Author-email: UBC Solar <strategy@ubcsolar.com>
@@ -42,7 +42,7 @@ License-File: LICENSE
42
42
  Requires-Dist: backports.tarfile ==1.2.0
43
43
  Requires-Dist: certifi ==2024.7.4
44
44
  Requires-Dist: charset-normalizer ==3.3.2
45
- Requires-Dist: dill ==0.3.8
45
+ Requires-Dist: dill >=0.3.8
46
46
  Requires-Dist: haversine ==2.8.1
47
47
  Requires-Dist: idna ==3.7
48
48
  Requires-Dist: importlib-metadata ==8.2.0
@@ -50,13 +50,13 @@ Requires-Dist: jaraco.classes ==3.4.0
50
50
  Requires-Dist: jaraco.context ==5.3.0
51
51
  Requires-Dist: jaraco.functools ==4.0.2
52
52
  Requires-Dist: keyring ==25.3.0
53
- Requires-Dist: llvmlite ==0.43.0
53
+ Requires-Dist: llvmlite
54
54
  Requires-Dist: markdown-it-py ==3.0.0
55
55
  Requires-Dist: mdurl ==0.1.2
56
56
  Requires-Dist: more-itertools ==10.4.0
57
57
  Requires-Dist: nh3 ==0.2.18
58
- Requires-Dist: numba ==0.60.0
59
- Requires-Dist: numpy ==2.0.1
58
+ Requires-Dist: numba
59
+ Requires-Dist: numpy >=2
60
60
  Requires-Dist: pkginfo ==1.10.0
61
61
  Requires-Dist: Pygments ==2.18.0
62
62
  Requires-Dist: readme-renderer ==44.0
@@ -67,6 +67,13 @@ Requires-Dist: rich ==13.7.1
67
67
  Requires-Dist: tqdm ==4.66.5
68
68
  Requires-Dist: urllib3 ==2.2.2
69
69
  Requires-Dist: zipp ==3.20.0
70
+ Requires-Dist: filterpy ==1.4.5
71
+ Requires-Dist: toml ==0.10.2
72
+ Requires-Dist: pandas
73
+ Requires-Dist: pydantic ==2.9.2
74
+ Requires-Dist: scipy
75
+ Requires-Dist: tomli
76
+ Requires-Dist: scipy-stubs
70
77
 
71
78
  # UBC Solar Physics
72
79
 
@@ -0,0 +1,57 @@
1
+ physics_rs.cpython-312-darwin.so,sha256=oyySBGSJsPlzzOICGez_N-ULun-QOad19iSeeICD4kg,699472
2
+ physics_rs/__init__.pyi,sha256=bMMIbLFgpSYq37i9xHpvdoVlMuI7IRZ9bdbLCcIBeO8,4235
3
+ physics/_version.py,sha256=Lv0gR-NbC-8DxwfmwXEmOzSq6Hgx6MH4xF1fYh_opXo,411
4
+ physics/lib.rs,sha256=BGgj8jwbWQ7mkBDfKyTqH5jZGKAAb9U0sSByUaI-Los,7169
5
+ physics/models.rs,sha256=N5342VhLaLSlPLHZ7s1VDIEPY76-rQN03lY_wd2HS1A,59
6
+ physics/__init__.py,sha256=7939mrehCy0ogupHq26hUk1MkAjh2xmbD30GscdC_D8,169
7
+ physics/environment.rs,sha256=VWX1haUCO-WenD0dawS5FxY9dquiUT6Uud3p3dAnJZA,34
8
+ physics/models/battery.rs,sha256=fTL9O20fQarT_CFsmMSqVEZNe_sTejWMaAR8Fc-z_ak,16
9
+ physics/models/lvs.rs,sha256=uyJ1ZZ1Phq8cWCzr2aevCWzt8MlhCw9DO5ObUvEs8ds,8
10
+ physics/models/constants.py,sha256=mw0IkjhSJe51inbbzvVpHnpGLY_AoWxIxjfjcUF4cd8,816
11
+ physics/models/motor.rs,sha256=Iya1C_YF09KMy-9N-Mt-rBf1EIAs2Bf3Q4eDvyFuAoc,10
12
+ physics/models/arrays.rs,sha256=rtthXq7PDjL30lIt8y9L2xFAPJE5o_ltmCbOGzzOxrc,11
13
+ physics/models/__init__.py,sha256=msz4YtXe7fsGr-FsV-yJK0frN5XrmsXPSAkpS8lxHW8,255
14
+ physics/models/regen.rs,sha256=WXwtzB72akG6L17wg-9Pz9kUe-57lqh4-PcSv1cKrGU,10
15
+ physics/models/lvs/basic_lvs.py,sha256=UH6VmVWrSo-tKvcbSOm3Ptp0edz1xDQiQsM4HlOJ__0,603
16
+ physics/models/lvs/lvs.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ physics/models/lvs/__init__.py,sha256=GkO6SJxbbSnXYLdMDvsvTRhXotV3zaRNmYBgziQLGB8,107
18
+ physics/models/lvs/base_lvs.py,sha256=PVwPgCaJ_TcV2mQf3X2pngi0aG-jTLTeloL-LQV3jMU,110
19
+ physics/models/motor/advanced_motor.py,sha256=EL86tCDSQCTT55EdXnmtPaIL9YS2o5p2u3QiLuoZuCA,8758
20
+ physics/models/motor/motor.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ physics/models/motor/__init__.py,sha256=zkV7LiAozFNu9CRWWXeCbCDepjsaUIYT8Q2dkXJgLsM,183
22
+ physics/models/motor/basic_motor.py,sha256=-_rKIFCRRLniC1yHr_8fRsmj6xvHuAzPqA168vTDkds,8626
23
+ physics/models/motor/base_motor.py,sha256=34wy8x945HvJijn9267fdAR_JNHxH_7bYxYbVl71WBA,97
24
+ physics/models/arrays/basic_array.py,sha256=cGBwyrYpR313ECJ-SwnrK3JzYo24NRE70j8sj-sxFQI,1332
25
+ physics/models/arrays/base_array.py,sha256=ZUjehd7vwNOBdFLUk9WJUeGOi9DPopYplH1gqAMnKgA,95
26
+ physics/models/arrays/arrays.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ physics/models/arrays/__init__.py,sha256=yavs1K3JA6x3Aa-U1JCZJlcWggCOFrVxrrMCGsiceAw,119
28
+ physics/models/battery/battery_config.toml,sha256=Fn1pb3NJJ_nclxm9nfGEQKmJYA2d5a9jCAUbwUGu6Uw,1092
29
+ physics/models/battery/battery.rs,sha256=10NAAGg99gQ70Kjd4kVuVHBxp3J6AgXfxEYKZUzu5DQ,5275
30
+ physics/models/battery/basic_battery.py,sha256=u0aO_iWKicVRECbDzLIs8goaWD5tLMnYGNe948lKC7U,5754
31
+ physics/models/battery/__init__.py,sha256=bIESRM8eEpaKSYMoliXD7rs3TUkAawTN9i3-YB2WCZg,630
32
+ physics/models/battery/battery_config.py,sha256=V4CfzUTcOFcizpDU9-Ujn2zXbUnAqrhyARN9QXGH6fk,4052
33
+ physics/models/battery/kalman_filter.py,sha256=kcX3SU1mNiY4-2YCUWAvqyTX6Cww7Pq7zaxaqh8ltgM,8725
34
+ physics/models/battery/base_battery.py,sha256=yK-bkA2OolE6nIDn5rf5nzi8gwm-AqQRmgsQioi_UOA,1203
35
+ physics/models/battery/battery_model.py,sha256=kODVlBZAIpPD_EB0UPlOeQv5HP-tMu6S-C6mEOJMHv4,10264
36
+ physics/models/regen/basic_regen.py,sha256=kcp6Wkw2o72xO_0-UCNABWSC_QIkexcS72iblNVQFBA,2350
37
+ physics/models/regen/base_regen.py,sha256=nWtmsm47wp9mx261OmSILwja32yYhzCLSNXWnzt82TY,95
38
+ physics/models/regen/__init__.py,sha256=51t_BHuQqIVPPy_0b14MO6QGZayOO326JR7wK1egy-g,119
39
+ physics/models/regen/regen.rs,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ physics/environment/__init__.py,sha256=eFWp8YFvL3CSXE5cZ24AcIjmW7vMUyh97sr9HZabw_U,210
41
+ physics/environment/gis.rs,sha256=9R7G0cjf5PxQAz-CSryA6-KGfrh1eSwRhJ6qF8KfjDE,12
42
+ physics/environment/environment.rs,sha256=yvzrjKHZ5vRvVip6lM34i8E0Ell_5fC3zyJDsb0h5nc,33
43
+ physics/environment/meteorology.rs,sha256=naWb7qYrtMkCE_tLAkM474fmxaufhCkyhy3TTUQ4Yw4,20
44
+ physics/environment/meteorology/__init__.py,sha256=569as2j7kpv8Nh75M9xk9e7rTqsDPGo3Ii3nskD6F34,154
45
+ physics/environment/meteorology/base_meteorology.py,sha256=d5TDNLUIBmTkLtJhv9qUq9KcfNKxzoM7xIOsfyNbwfI,2418
46
+ physics/environment/meteorology/irradiant_meteorology.py,sha256=1kqX4nEOUw-CYrLTusG6BdoZbZt_GEpfKMyey8YzLr0,5615
47
+ physics/environment/meteorology/clouded_meteorology.py,sha256=aEqlozaMOyhhxGK7CCD6BVHAn_HZDpSAUwGUngikkp4,27665
48
+ physics/environment/meteorology/meteorology.rs,sha256=Q3toiZv8M1updhoAnFDZ87YPy1afC9chUkF2IP9uA-I,5004
49
+ physics/environment/gis/base_gis.py,sha256=eVr4G7wAGlx6VsrCt2OuI8WzUMM50h2sHHvw8BOBur8,1046
50
+ physics/environment/gis/__init__.py,sha256=Kp85UC1WvcAMBxbgvwaMTEk8ELYzwUJLCtP0e1hnMvM,90
51
+ physics/environment/gis/gis.rs,sha256=_vXYMr7vNCC8Ip3CpQdyl6FA_3tCvOZeJd0-J5t4Eps,4865
52
+ physics/environment/gis/gis.py,sha256=EAFDudUmLWCBtM5A_LO3-MV-98tj-Q3s7S2WaoJjUGg,13209
53
+ ubc_solar_physics-1.7.3.dist-info/RECORD,,
54
+ ubc_solar_physics-1.7.3.dist-info/LICENSE,sha256=DAej6EJNqQWTair3XPAQiqoJbly4BAT1JMOsZxoZvH0,1066
55
+ ubc_solar_physics-1.7.3.dist-info/WHEEL,sha256=bLTZ97GHgNCMYeF-qxK_tNAlmPyT5vBPkIlfVrEr9lQ,109
56
+ ubc_solar_physics-1.7.3.dist-info/top_level.txt,sha256=jBZ5oyp1QQOrKodHG2UH9PMPEiZtza_q3y6fp3lEmQs,19
57
+ ubc_solar_physics-1.7.3.dist-info/METADATA,sha256=GNE035peFVy6NH3Fy6Posh3nim_JTJhlgcV1BDtljeU,5002
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (74.1.3)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp312-cp312-macosx_11_0_arm64
5
5
 
@@ -0,0 +1,2 @@
1
+ physics
2
+ physics_rs
Binary file
@@ -1,89 +0,0 @@
1
- """
2
- This class collects the constants that are related to a specific competition.
3
- """
4
- import pathlib
5
-
6
- import numpy as np
7
- import pickle
8
- import enum
9
- import json
10
- import os
11
-
12
-
13
- class Race:
14
- class RaceType(enum.Enum):
15
- ASC = "ASC"
16
- FSGP = "FSGP"
17
-
18
- def __str__(self):
19
- match self.value:
20
- case "ASC":
21
- return "ASC"
22
- case "FSGP":
23
- return "FSGP"
24
-
25
- def __reduce__(self):
26
- return self.__class__, (self.name,)
27
-
28
- def __contains__(self, item):
29
- return item == "ASC" or item == "FSGP"
30
-
31
- def __repr__(self):
32
- return str(self)
33
-
34
- ASC = RaceType.ASC
35
- FSGP = RaceType.FSGP
36
-
37
- def __init__(self, race_type: RaceType, race_constants: dict):
38
- self.race_type = race_type
39
-
40
- self.days = race_constants["days"]
41
- self.tiling = race_constants["tiling"]
42
- self.date = (race_constants["start_year"], race_constants["start_month"], race_constants["start_day"])
43
-
44
- self.race_duration = len(self.days) * 24 * 60 * 60 # Duration (s)
45
- self.driving_boolean = self.make_time_boolean("driving")
46
- self.charging_boolean = self.make_time_boolean("charging")
47
-
48
- def __str__(self):
49
- return str(self.race_type)
50
-
51
- def write(self, race_directory: pathlib.Path):
52
- with open(race_directory / f"{str(self.race_type)}.pkl", 'wb') as outfile:
53
- pickle.dump(self, outfile, protocol=pickle.HIGHEST_PROTOCOL)
54
-
55
- def make_time_boolean(self, boolean_type: str):
56
- boolean: np.ndarray = np.empty(self.race_duration, dtype=np.int8)
57
- DAY_LENGTH: int = 24 * 60 * 60 # Length of a day in seconds
58
-
59
- for tick in range(len(boolean)):
60
- day: int = tick // DAY_LENGTH # Integer division to determine how many days have passed
61
- time_of_day = tick % DAY_LENGTH # Time of day in seconds where 0 is midnight and 43200 is noon
62
- begin, end = self.days[str(day)][boolean_type]
63
-
64
- # If the time of day is between the beginning and end, then the boolean is True, else False
65
- boolean[tick] = begin <= time_of_day < end
66
-
67
- return boolean
68
-
69
-
70
- def load_race(race_type: Race.RaceType, race_directory: pathlib.Path) -> Race:
71
- with open(race_directory / f"{str(race_type)}.pkl", 'rb') as infile:
72
- return pickle.load(infile)
73
-
74
-
75
- def compile_races(config_directory: pathlib.Path, race_directory: pathlib.Path):
76
- fsgp_config_path = os.path.join(config_directory, f"settings_FSGP.json")
77
- asc_config_path = os.path.join(config_directory, f"settings_ASC.json")
78
-
79
- with open(fsgp_config_path) as f:
80
- fsgp_race_constants = json.load(f)
81
-
82
- with open(asc_config_path) as f:
83
- asc_race_constants = json.load(f)
84
-
85
- fsgp = Race(Race.FSGP, fsgp_race_constants)
86
- fsgp.write(race_directory)
87
-
88
- asc = Race(Race.ASC, asc_race_constants)
89
- asc.write(race_directory)