ubc-solar-physics 1.0.3__cp39-cp39-win32.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 (52) hide show
  1. core.cp39-win32.pyd +0 -0
  2. physics/__init__.py +12 -0
  3. physics/__version__.py +16 -0
  4. physics/environment/__init__.py +22 -0
  5. physics/environment/environment.rs +2 -0
  6. physics/environment/gis/__init__.py +7 -0
  7. physics/environment/gis/base_gis.py +24 -0
  8. physics/environment/gis/gis.py +337 -0
  9. physics/environment/gis/gis.rs +25 -0
  10. physics/environment/gis.rs +1 -0
  11. physics/environment/meteorology/__init__.py +3 -0
  12. physics/environment/meteorology/base_meteorology.py +69 -0
  13. physics/environment/meteorology/clouded_meteorology.py +601 -0
  14. physics/environment/meteorology/irradiant_meteorology.py +106 -0
  15. physics/environment/meteorology/meteorology.rs +138 -0
  16. physics/environment/meteorology.rs +1 -0
  17. physics/environment/race.py +89 -0
  18. physics/environment.rs +2 -0
  19. physics/lib.rs +98 -0
  20. physics/models/__init__.py +13 -0
  21. physics/models/arrays/__init__.py +7 -0
  22. physics/models/arrays/arrays.rs +0 -0
  23. physics/models/arrays/base_array.py +6 -0
  24. physics/models/arrays/basic_array.py +39 -0
  25. physics/models/arrays.rs +1 -0
  26. physics/models/battery/__init__.py +7 -0
  27. physics/models/battery/base_battery.py +29 -0
  28. physics/models/battery/basic_battery.py +141 -0
  29. physics/models/battery/battery.rs +0 -0
  30. physics/models/battery.rs +1 -0
  31. physics/models/constants.py +23 -0
  32. physics/models/lvs/__init__.py +7 -0
  33. physics/models/lvs/base_lvs.py +6 -0
  34. physics/models/lvs/basic_lvs.py +18 -0
  35. physics/models/lvs/lvs.rs +0 -0
  36. physics/models/lvs.rs +1 -0
  37. physics/models/motor/__init__.py +7 -0
  38. physics/models/motor/base_motor.py +6 -0
  39. physics/models/motor/basic_motor.py +174 -0
  40. physics/models/motor/motor.rs +0 -0
  41. physics/models/motor.rs +1 -0
  42. physics/models/regen/__init__.py +7 -0
  43. physics/models/regen/base_regen.py +6 -0
  44. physics/models/regen/basic_regen.py +39 -0
  45. physics/models/regen/regen.rs +0 -0
  46. physics/models/regen.rs +1 -0
  47. physics/models.rs +5 -0
  48. ubc_solar_physics-1.0.3.dist-info/LICENSE +21 -0
  49. ubc_solar_physics-1.0.3.dist-info/METADATA +136 -0
  50. ubc_solar_physics-1.0.3.dist-info/RECORD +52 -0
  51. ubc_solar_physics-1.0.3.dist-info/WHEEL +5 -0
  52. ubc_solar_physics-1.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,141 @@
1
+ import numpy as np
2
+ from numpy.polynomial import Polynomial
3
+
4
+ from physics.models.battery.base_battery import BaseBattery
5
+
6
+
7
+ class BasicBattery(BaseBattery):
8
+ """
9
+ Class representing the DayBreak battery pack.
10
+
11
+ Attributes:
12
+ max_voltage (float): maximum voltage of the DayBreak battery pack (V)
13
+ min_voltage (float): minimum voltage of the DayBreak battery pack (V)
14
+ max_current_capacity (float): nominal capacity of the DayBreak battery pack (Ah)
15
+ max_energy_capacity (float): nominal energy capacity of the DayBreak battery pack (Wh)
16
+
17
+ state_of_charge (float): instantaneous battery state-of-charge (0.00 - 1.00)
18
+ discharge_capacity (float): instantaneous amount of charge extracted from battery (Ah)
19
+ voltage (float): instantaneous voltage of the battery (V)
20
+ stored_energy (float): instantaneous energy stored in the battery (Wh)
21
+ """
22
+
23
+ def __init__(self, state_of_charge, max_voltage, min_voltage, max_current_capacity, max_energy_capacity):
24
+ """
25
+
26
+ Constructor for BasicBattery class.
27
+
28
+ :param float state_of_charge: initial battery state of charge
29
+
30
+ """
31
+
32
+ # ----- DayBreak battery constants -----
33
+
34
+ self.max_voltage = max_voltage
35
+ self.min_voltage = min_voltage
36
+ self.max_current_capacity = max_current_capacity
37
+ self.max_energy_capacity = max_energy_capacity
38
+
39
+ # ----- DayBreak battery equations -----
40
+
41
+ self.calculate_voltage_from_discharge_capacity = calculate_voltage_from_discharge_capacity()
42
+
43
+ self.calculate_energy_from_discharge_capacity = calculate_energy_from_discharge_capacity()
44
+
45
+ self.calculate_soc_from_discharge_capacity = calculate_soc_from_discharge_capacity(self.max_current_capacity)
46
+
47
+ self.calculate_discharge_capacity_from_soc = calculate_discharge_capacity_from_soc(self.max_current_capacity)
48
+
49
+ self.calculate_discharge_capacity_from_energy = calculate_discharge_capacity_from_energy()
50
+
51
+ # ----- DayBreak battery variables -----
52
+
53
+ self.state_of_charge = state_of_charge
54
+
55
+ # SOC -> discharge_capacity
56
+ self.discharge_capacity = self.calculate_discharge_capacity_from_soc(self.state_of_charge)
57
+
58
+ # discharge_capacity -> voltage
59
+ self.voltage = self.calculate_voltage_from_discharge_capacity(self.discharge_capacity)
60
+
61
+ # discharge_capacity -> energy
62
+ self.stored_energy = self.max_energy_capacity - self.calculate_energy_from_discharge_capacity(
63
+ self.discharge_capacity)
64
+
65
+ # ----- DayBreak battery initialisation -----
66
+
67
+ super().__init__(self.stored_energy, self.max_current_capacity, self.max_energy_capacity,
68
+ self.max_voltage, self.min_voltage, self.voltage, self.state_of_charge)
69
+
70
+ def update_array(self, cumulative_energy_array):
71
+ """
72
+ Performs energy calculations with NumPy arrays
73
+
74
+ :param cumulative_energy_array: a NumPy array containing the cumulative energy changes at each time step
75
+ experienced by the battery
76
+
77
+ :return: soc_array – a NumPy array containing the battery state of charge at each time step
78
+
79
+ :return: voltage_array – a NumPy array containing the voltage of the battery at each time step
80
+
81
+ :return: stored_energy_array– a NumPy array containing the energy stored in the battery at each time step
82
+
83
+ """
84
+
85
+ stored_energy_array = np.full_like(cumulative_energy_array, fill_value=self.stored_energy)
86
+ stored_energy_array += cumulative_energy_array / 3600
87
+ stored_energy_array = np.clip(stored_energy_array, a_min=0, a_max=self.max_energy_capacity)
88
+
89
+ energy_discharged_array = np.full_like(cumulative_energy_array, fill_value=self.max_energy_capacity) - \
90
+ stored_energy_array
91
+
92
+ discharge_capacity_array = self.calculate_discharge_capacity_from_energy(energy_discharged_array)
93
+
94
+ soc_array = self.calculate_soc_from_discharge_capacity(discharge_capacity_array)
95
+ voltage_array = self.calculate_voltage_from_discharge_capacity(discharge_capacity_array)
96
+
97
+ return soc_array, voltage_array, stored_energy_array
98
+
99
+ def get_raw_soc(self, cumulative_energy_array):
100
+ """
101
+
102
+ Return the not truncated (SOC is allowed to go above 100% and below 0%) state of charge.
103
+
104
+ :param np.ndarray cumulative_energy_array: a NumPy array containing the cumulative energy changes at each time step
105
+ experienced by the battery
106
+
107
+ :return: a NumPy array containing the battery state of charge at each time step
108
+ :rtype: np.ndarray
109
+
110
+ """
111
+
112
+ stored_energy_array = np.full_like(cumulative_energy_array, fill_value=self.stored_energy)
113
+ stored_energy_array += cumulative_energy_array / 3600
114
+
115
+ energy_discharged_array = np.full_like(cumulative_energy_array, fill_value=self.max_energy_capacity) - stored_energy_array
116
+
117
+ discharge_capacity_array = self.calculate_discharge_capacity_from_energy(energy_discharged_array)
118
+
119
+ soc_array = self.calculate_soc_from_discharge_capacity(discharge_capacity_array)
120
+
121
+ return soc_array
122
+
123
+
124
+ def calculate_voltage_from_discharge_capacity():
125
+ return Polynomial([117.6, -0.858896]) # -0.8589x + 117.6
126
+
127
+
128
+ def calculate_energy_from_discharge_capacity():
129
+ return Polynomial([0, 117.6, -0.429448]) # -0.4294x^2 + 117.6x
130
+
131
+
132
+ def calculate_soc_from_discharge_capacity(max_current_capacity):
133
+ return Polynomial([1, -1 / max_current_capacity])
134
+
135
+
136
+ def calculate_discharge_capacity_from_soc(max_current_capacity):
137
+ return Polynomial([max_current_capacity, -max_current_capacity])
138
+
139
+
140
+ def calculate_discharge_capacity_from_energy():
141
+ return lambda x: 136.92 - np.sqrt(18747.06027 - 2.32857 * x)
File without changes
@@ -0,0 +1 @@
1
+ mod battery;
@@ -0,0 +1,23 @@
1
+ # Radius of the Earth (m)
2
+ EARTH_RADIUS = 6371009
3
+
4
+ # Acceleration caused by gravity (m/s^2)
5
+ ACCELERATION_G = 9.81
6
+
7
+ # Density of Air at 15C and 101kPa (kg/m^3)
8
+ AIR_DENSITY = 1.225
9
+
10
+ # Maximum number of waypoints that can be given to generate route data
11
+ MAX_WAYPOINTS = 10
12
+
13
+ # Solar Irradiance (W/m^2)
14
+ SOLAR_IRRADIANCE = 1353
15
+
16
+ # As we currently have a limited number of API calls(60) every minute with the
17
+ # current Weather API, we must shrink the dataset significantly. As the
18
+ # OpenWeatherAPI models have a resolution of between 2.5 - 70 km, we will
19
+ # go for a resolution of 25km. Assuming we travel at 100km/h for 12 hours,
20
+ # 1200 kilometres/25 = 48 API calls
21
+ # As the Google Maps API has a resolution of around 40m between points,
22
+ # for ASC, we must cull at 625:1 (because 25,000m / 40m = 625)
23
+ REDUCTION_FACTOR = 625
@@ -0,0 +1,7 @@
1
+ from .base_lvs import BaseLVS
2
+ from .basic_lvs import BasicLVS
3
+
4
+ __all__ = [
5
+ "BaseLVS",
6
+ "BasicLVS"
7
+ ]
@@ -0,0 +1,6 @@
1
+ from abc import ABC
2
+
3
+
4
+ class BaseLVS(ABC):
5
+ def __init__(self, consumed_energy):
6
+ super().__init__()
@@ -0,0 +1,18 @@
1
+ from physics.models.lvs.base_lvs import BaseLVS
2
+
3
+
4
+ class BasicLVS(BaseLVS):
5
+
6
+ def __init__(self, consumed_energy, lvs_current, lvs_voltage):
7
+ super().__init__(consumed_energy)
8
+ self.lvs_current = lvs_current
9
+ self.lvs_voltage = lvs_voltage
10
+
11
+ def get_consumed_energy(self, tick):
12
+ """
13
+ Get the energy consumption of the Low Voltage System (current * voltage * time)
14
+
15
+ :param tick - (int) tick time passed
16
+ :returns: consumed_energy - (number) value of energy consumed
17
+ """
18
+ return self.lvs_current * self.lvs_voltage * tick
File without changes
physics/models/lvs.rs ADDED
@@ -0,0 +1 @@
1
+ mod lvs;
@@ -0,0 +1,7 @@
1
+ from .base_motor import BaseMotor
2
+ from .basic_motor import BasicMotor
3
+
4
+ __all__ = [
5
+ "BaseMotor",
6
+ "BasicMotor"
7
+ ]
@@ -0,0 +1,6 @@
1
+ from abc import ABC
2
+
3
+
4
+ class BaseMotor(ABC):
5
+ def __init__(self):
6
+ super().__init__()
@@ -0,0 +1,174 @@
1
+ import math
2
+ import numpy as np
3
+
4
+ from physics.models.motor.base_motor import BaseMotor
5
+ from physics.models.constants import ACCELERATION_G, AIR_DENSITY
6
+
7
+
8
+ class BasicMotor(BaseMotor):
9
+ def __init__(self, vehicle_mass, road_friction, tire_radius, vehicle_frontal_area, drag_coefficient):
10
+ super().__init__()
11
+
12
+ # Instantaneous voltage supplied by the battery to the motor controller
13
+ self.dc_v = 0
14
+
15
+ # Instantaneous current supplied by the battery to the motor controller
16
+ self.dc_i = 0
17
+
18
+ self.input_power = 0
19
+ self.vehicle_mass = vehicle_mass
20
+ self.acceleration_g = ACCELERATION_G
21
+ self.road_friction = road_friction
22
+ self.tire_radius = tire_radius
23
+
24
+ self.air_density = AIR_DENSITY
25
+ self.vehicle_frontal_area = vehicle_frontal_area
26
+ self.drag_coefficient = drag_coefficient
27
+
28
+ self.friction_force = (self.vehicle_mass * self.acceleration_g * self.road_friction)
29
+
30
+ self.e_mc = 0.98 # motor controller efficiency, subject to change
31
+ self.e_m = 0.9 # motor efficiency, subject to change
32
+
33
+ # print("torque experienced by motor: {} Nm".format(self.constant_torque))
34
+
35
+ @staticmethod
36
+ def calculate_motor_efficiency(motor_angular_speed, motor_output_energy, tick):
37
+ """
38
+
39
+ Calculates a NumPy array of motor efficiency from NumPy array of operating angular speeds and NumPy array
40
+ of output power. Based on data obtained from NGM SC-M150 Datasheet and modelling done in MATLAB
41
+
42
+ r squared value: 0.873
43
+
44
+ :param np.ndarray motor_angular_speed: (float[N]) angular speed motor operates in rad/s
45
+ :param np.ndarray motor_output_energy: (float[N]) energy motor outputs to the wheel in J
46
+ :param float tick: length of 1 update cycle in seconds
47
+ :returns e_m: (float[N]) efficiency of the motor
48
+ :rtype: np.ndarray
49
+
50
+ """
51
+
52
+ # Power = Energy / Time
53
+ motor_output_power = motor_output_energy * tick
54
+ rads_rpm_conversion_factor = 30 / math.pi
55
+
56
+ revolutions_per_minute = motor_angular_speed * rads_rpm_conversion_factor
57
+
58
+ e_m = calculate_motor_efficiency(motor_output_power, revolutions_per_minute)
59
+
60
+ e_m[e_m < 0.7382] = 0.7382
61
+ e_m[e_m > 1] = 1
62
+
63
+ return e_m
64
+
65
+ @staticmethod
66
+ def calculate_motor_controller_efficiency(motor_angular_speed, motor_output_energy, tick):
67
+ """
68
+
69
+ Calculates a NumPy array of motor controller efficiency from NumPy array of operating angular speeds and
70
+ NumPy array of output power. Based on data obtained from the WaveSculptor Motor Controller Datasheet efficiency
71
+ curve for a 90 V DC Bus and modelling done in MATLAB.
72
+
73
+ r squared value: 0.7431
74
+
75
+ :param np.ndarray motor_angular_speed: (float[N]) angular speed motor operates in rad/s
76
+ :param np.ndarray motor_output_energy: (float[N]) energy motor outputs to the wheel in J
77
+ :param float tick: length of 1 update cycle in seconds
78
+ :returns e_mc (float[N]) efficiency of the motor controller
79
+ :rtype: np.ndarray
80
+
81
+ """
82
+
83
+ # Ignore nan warning. Set nan value to 0
84
+ np.seterr(divide='ignore', invalid='ignore')
85
+
86
+ # Power = Energy / Time
87
+ motor_output_power = motor_output_energy / tick
88
+
89
+ # Torque = Power / Angular Speed
90
+ motor_torque_array = np.nan_to_num(motor_output_power / motor_angular_speed)
91
+
92
+ np.seterr(divide='warn', invalid='warn')
93
+
94
+ e_mc = calculate_motor_controller_efficiency(motor_angular_speed, motor_torque_array)
95
+
96
+ e_mc[e_mc < 0.9] = 0.9
97
+ e_mc[e_mc > 1] = 1
98
+
99
+ return e_mc
100
+
101
+ def calculate_energy_in(self, required_speed_kmh, gradients, wind_speeds, tick):
102
+ """
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
+
114
+ """
115
+ required_speed_ms = required_speed_kmh / 3.6
116
+
117
+ acceleration_ms2 = np.clip(np.gradient(required_speed_ms), a_min=0, a_max=None)
118
+ acceleration_force = acceleration_ms2 * self.vehicle_mass
119
+
120
+ required_angular_speed_rads = required_speed_ms / self.tire_radius
121
+
122
+ drag_forces = 0.5 * self.air_density * (
123
+ (required_speed_ms + wind_speeds) ** 2) * self.drag_coefficient * self.vehicle_frontal_area
124
+
125
+ angles = np.arctan(gradients)
126
+ g_forces = self.vehicle_mass * self.acceleration_g * np.sin(angles)
127
+
128
+ road_friction_array = self.road_friction * self.vehicle_mass * self.acceleration_g * np.cos(angles)
129
+
130
+ net_force = road_friction_array + drag_forces + g_forces + acceleration_force
131
+
132
+ motor_output_energies = required_angular_speed_rads * net_force * self.tire_radius * tick
133
+ motor_output_energies = np.clip(motor_output_energies, a_min=0, a_max=None)
134
+
135
+ e_m = self.calculate_motor_efficiency(required_angular_speed_rads, motor_output_energies, tick)
136
+ e_mc = self.calculate_motor_controller_efficiency(required_angular_speed_rads, motor_output_energies, tick)
137
+
138
+ motor_controller_input_energies = motor_output_energies / (e_m * e_mc)
139
+
140
+ # Filter out and replace negative energy consumption as 0
141
+ motor_controller_input_energies = np.where(motor_controller_input_energies > 0,
142
+ motor_controller_input_energies, 0)
143
+
144
+ return motor_controller_input_energies
145
+
146
+ def __str__(self):
147
+ return (f"Tire radius: {self.tire_radius}m\n"
148
+ f"Rolling resistance coefficient: {self.road_friction}\n"
149
+ f"Vehicle mass: {self.vehicle_mass}kg\n"
150
+ f"Acceleration of gravity: {self.acceleration_g}m/s^2\n"
151
+ f"Motor controller efficiency: {self.e_mc}%\n"
152
+ f"Motor efficiency: {self.e_m}%\n")
153
+
154
+
155
+ def calculate_motor_efficiency(motor_output_power, revolutions_per_minute):
156
+ return 0.7382 - (6.281e-5 * motor_output_power) + (6.708e-4 * revolutions_per_minute) \
157
+ - (2.89e-8 * motor_output_power ** 2) + (2.416e-7 * motor_output_power * revolutions_per_minute) \
158
+ - (8.672e-7 * revolutions_per_minute ** 2) + (5.653e-12 * motor_output_power ** 3) \
159
+ - (1.74e-11 * motor_output_power ** 2 * revolutions_per_minute) \
160
+ - (7.322e-11 * motor_output_power * revolutions_per_minute ** 2) \
161
+ + (3.263e-10 * revolutions_per_minute ** 3)
162
+
163
+
164
+ def calculate_motor_controller_efficiency(motor_angular_speed, motor_torque_array):
165
+ return 0.7694 + (0.007818 * motor_angular_speed) + (0.007043 * motor_torque_array) \
166
+ - (1.658e-4 * motor_angular_speed ** 2) - (1.806e-5 * motor_torque_array * motor_angular_speed) \
167
+ - (1.909e-4 * motor_torque_array ** 2) + (1.602e-6 * motor_angular_speed ** 3) \
168
+ + (4.236e-7 * motor_angular_speed ** 2 * motor_torque_array) \
169
+ - (2.306e-7 * motor_angular_speed * motor_torque_array ** 2) \
170
+ + (2.122e-06 * motor_torque_array ** 3) - (5.701e-09 * motor_angular_speed ** 4) \
171
+ - (2.054e-9 * motor_angular_speed ** 3 * motor_torque_array) \
172
+ - (3.126e-10 * motor_angular_speed ** 2 * motor_torque_array ** 2) \
173
+ + (1.708e-09 * motor_angular_speed * motor_torque_array ** 3) \
174
+ - (8.094e-09 * motor_torque_array ** 4)
File without changes
@@ -0,0 +1 @@
1
+ mod motor;
@@ -0,0 +1,7 @@
1
+ from .base_regen import BaseRegen
2
+ from .basic_regen import BasicRegen
3
+
4
+ __all__ = [
5
+ "BasicRegen",
6
+ "BaseRegen"
7
+ ]
@@ -0,0 +1,6 @@
1
+ from abc import ABC
2
+
3
+
4
+ class BaseRegen(ABC):
5
+ def __init__(self):
6
+ super().__init__()
@@ -0,0 +1,39 @@
1
+ from physics.models.regen import BaseRegen
2
+ import numpy as np
3
+
4
+
5
+ class BasicRegen(BaseRegen):
6
+ GRAVITY = 9.81
7
+ EFFICIENCY = 0.5 # currently set to 50% but best case scenario is 60-70%
8
+
9
+ def __init__(self, vehicle_mass):
10
+ super().__init__()
11
+ self.min_decel_mag = 0
12
+ self.vehicle_mass = vehicle_mass
13
+ self.kmh_to_mps = 0.278
14
+
15
+ def calculate_produced_energy(self, speed_kmh, gis_route_elevations, min_regen_speed, max_power):
16
+ """
17
+ Returns a numpy array containing the energy produced by regen
18
+ during each tick of the race based on the change in energy in that tick
19
+ :param speed_kmh: an array containing the speeds at each tick
20
+ :param gis_route_elevations: an array containing elevations on the route at each tick
21
+ """
22
+ # get the changes of energy from tick i to tick i + 1
23
+ speed_ms = speed_kmh / 3.6 # Convert to m/s from km/h
24
+ delta_kinetic_energy = np.diff((1 / 2) * self.vehicle_mass * pow(speed_ms, 2), append=[0])
25
+ delta_potential_energy = np.diff(self.vehicle_mass * self.GRAVITY * gis_route_elevations, append=[0])
26
+
27
+ # get the total change in energy at each tick
28
+ delta_energy = delta_kinetic_energy + delta_potential_energy
29
+
30
+ # create regen energy produced array
31
+ # 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)
33
+
34
+ # Regen does not occur below a certain speed
35
+ produced_energy = np.where(speed_ms >= min_regen_speed, produced_energy, 0)
36
+
37
+ # Regen power is capped by current limitations
38
+
39
+ return np.clip(produced_energy, a_min=0, a_max=max_power)
File without changes
@@ -0,0 +1 @@
1
+ mod regen;
physics/models.rs ADDED
@@ -0,0 +1,5 @@
1
+ mod arrays;
2
+ mod battery;
3
+ mod lvs;
4
+ mod motor;
5
+ mod regen;
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 UBC Solar
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.
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.1
2
+ Name: ubc-solar-physics
3
+ Version: 1.0.3
4
+ Summary: UBC Solar's Simulation Environment
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
+ Author-email: UBC Solar <strategy@ubcsolar.com>
7
+ Maintainer: Renu Rajamagmesh, Felix Toft, Mack Wilson, Jonah Lee, Tamzeed Quazi
8
+ Maintainer-email: UBC Solar <strategy@ubcsolar.com>, Joshua Riefman <joshuariefman@gmail.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2024 UBC Solar
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+
31
+ Project-URL: Homepage, https://ubcsolar.com
32
+ Project-URL: Repository, https://github.com/UBC-Solar/physics
33
+ Project-URL: Documentation, https://ubc-solar-physics.readthedocs.io/en/latest/
34
+ Keywords: car,simulation,solar
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Rust
37
+ Classifier: Natural Language :: English
38
+ Classifier: Topic :: Scientific/Engineering :: Physics
39
+ Requires-Python: >=3.9
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: backports.tarfile ==1.2.0
43
+ Requires-Dist: certifi ==2024.7.4
44
+ Requires-Dist: charset-normalizer ==3.3.2
45
+ Requires-Dist: dill ==0.3.8
46
+ Requires-Dist: haversine ==2.8.1
47
+ Requires-Dist: idna ==3.7
48
+ Requires-Dist: importlib-metadata ==8.2.0
49
+ Requires-Dist: jaraco.classes ==3.4.0
50
+ Requires-Dist: jaraco.context ==5.3.0
51
+ Requires-Dist: jaraco.functools ==4.0.2
52
+ Requires-Dist: keyring ==25.3.0
53
+ Requires-Dist: llvmlite ==0.43.0
54
+ Requires-Dist: markdown-it-py ==3.0.0
55
+ Requires-Dist: maturin ==1.7.0
56
+ Requires-Dist: mdurl ==0.1.2
57
+ Requires-Dist: more-itertools ==10.4.0
58
+ Requires-Dist: nh3 ==0.2.18
59
+ Requires-Dist: numba ==0.60.0
60
+ Requires-Dist: numpy ==2.0.1
61
+ Requires-Dist: pkginfo ==1.10.0
62
+ Requires-Dist: Pygments ==2.18.0
63
+ Requires-Dist: readme-renderer ==44.0
64
+ Requires-Dist: requests ==2.32.3
65
+ Requires-Dist: requests-toolbelt ==1.0.0
66
+ Requires-Dist: rfc3986 ==2.0.0
67
+ Requires-Dist: rich ==13.7.1
68
+ Requires-Dist: tqdm ==4.66.5
69
+ Requires-Dist: urllib3 ==2.2.2
70
+ Requires-Dist: zipp ==3.20.0
71
+
72
+ # UBC Solar Physics
73
+
74
+ <!-- marker-index-start -->
75
+
76
+ [![Documentation Status](https://readthedocs.org/projects/ubc-solar-physics/badge/?version=latest)](https://ubc-solar-physics.readthedocs.io/en/latest/?badge=latest)
77
+
78
+ UBC Solar's physics and environment models for simulating our groundbreaking solar cars.
79
+
80
+ The API is currently unstable, and backwards compatibility may not be maintained.
81
+
82
+ ## Requirements
83
+
84
+ Versions indicated are recommended
85
+
86
+ * Git [^1]
87
+ * Python >=3.9 [^2]
88
+ * Rustc >=1.79.0 [^3]
89
+ * Cargo >=1.79.0 [^4]
90
+
91
+ ## Installation
92
+
93
+ First, clone this repository.
94
+
95
+ ```bash
96
+ git clone https://github.com/UBC-Solar/physics.git
97
+ ```
98
+ Then, create and activate a virtual environment.
99
+ Next, install dependencies in editable mode.
100
+
101
+ ```bash
102
+ pip3 install -e .
103
+ ```
104
+
105
+ ## Getting Started
106
+
107
+ Example of calculating solar arrays produced energy
108
+
109
+ ```python
110
+ from physics.models.arrays import BasicArray
111
+ import numpy as np
112
+
113
+ efficiency = 0.25 # 25.0% efficient
114
+ panel_size = 4.0 # 4.0m^2 of panels
115
+ tick = 1.0 # 1.0s interval
116
+
117
+ arrays = BasicArray(panel_efficiency=efficiency, panel_size=panel_size)
118
+
119
+ irradiance = np.full([5], 400.0) # 10 seconds of 400.0W/m^2 irradiance
120
+
121
+ solar_power_produced = arrays.calculate_produced_energy(solar_irradiance=irradiance, tick=tick)
122
+
123
+ assert np.array_equal(solar_power_produced, np.array([400.0, 400.0, 400.0, 400.0, 400.0]))
124
+ ```
125
+
126
+ ## Appendix
127
+
128
+ [^1]: use `git --version` to verify version
129
+
130
+ [^2]: use `python3 --version` to verify version
131
+
132
+ [^3]: use `rustc --version` to verify version
133
+
134
+ [^4]: use `cargo --version` to verify version
135
+
136
+ <!-- marker-index-end -->