machwave 0.1.0__py3-none-any.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 (61) hide show
  1. machwave/models/__init__.py +0 -0
  2. machwave/models/atmosphere/__init__.py +87 -0
  3. machwave/models/atmosphere/atm_1976.py +86 -0
  4. machwave/models/materials/__init__.py +37 -0
  5. machwave/models/materials/metals.py +86 -0
  6. machwave/models/materials/polymers.py +50 -0
  7. machwave/models/propulsion/__init__.py +209 -0
  8. machwave/models/propulsion/grain/__init__.py +342 -0
  9. machwave/models/propulsion/grain/fmm/_2d.py +187 -0
  10. machwave/models/propulsion/grain/fmm/_3d.py +157 -0
  11. machwave/models/propulsion/grain/fmm/__init__.py +162 -0
  12. machwave/models/propulsion/grain/fmm/services.py +227 -0
  13. machwave/models/propulsion/grain/fmm/stl.py +68 -0
  14. machwave/models/propulsion/grain/geometries/__init__.py +17 -0
  15. machwave/models/propulsion/grain/geometries/bates.py +74 -0
  16. machwave/models/propulsion/grain/geometries/conical.py +55 -0
  17. machwave/models/propulsion/grain/geometries/d_grain.py +40 -0
  18. machwave/models/propulsion/grain/geometries/multi_port.py +64 -0
  19. machwave/models/propulsion/grain/geometries/rod_and_tube.py +53 -0
  20. machwave/models/propulsion/grain/geometries/star.py +67 -0
  21. machwave/models/propulsion/grain/geometries/wagon_wheel.py +81 -0
  22. machwave/models/propulsion/propellants/__init__.py +17 -0
  23. machwave/models/propulsion/propellants/solid.py +260 -0
  24. machwave/models/propulsion/structure/__init__.py +16 -0
  25. machwave/models/propulsion/structure/chamber.py +222 -0
  26. machwave/models/propulsion/structure/nozzle.py +73 -0
  27. machwave/models/propulsion/thermals.py +14 -0
  28. machwave/models/recovery/__init__.py +58 -0
  29. machwave/models/recovery/events.py +116 -0
  30. machwave/models/recovery/parachutes.py +105 -0
  31. machwave/models/rocket/__init__.py +91 -0
  32. machwave/models/rocket/fuselage.py +89 -0
  33. machwave/montecarlo/__init__.py +255 -0
  34. machwave/montecarlo/random.py +184 -0
  35. machwave/operations/__init__.py +33 -0
  36. machwave/operations/ballistics/_1dof.py +188 -0
  37. machwave/operations/ballistics/__init__.py +28 -0
  38. machwave/operations/internal_ballistics/__init__.py +423 -0
  39. machwave/services/__init__.py +0 -0
  40. machwave/services/common.py +5 -0
  41. machwave/services/conversions.py +64 -0
  42. machwave/services/decorators.py +62 -0
  43. machwave/services/equations.py +81 -0
  44. machwave/services/export_formats.py +63 -0
  45. machwave/services/factories.py +28 -0
  46. machwave/services/isentropic_flow.py +388 -0
  47. machwave/services/math/__init__.py +0 -0
  48. machwave/services/math/geometric.py +115 -0
  49. machwave/services/numpy.py +22 -0
  50. machwave/services/plots/__init__.py +0 -0
  51. machwave/services/plots/ballistics.py +52 -0
  52. machwave/services/plots/internal_ballistics.py +83 -0
  53. machwave/simulations/__init__.py +69 -0
  54. machwave/simulations/ballistics.py +147 -0
  55. machwave/simulations/internal_balistics_coupled.py +151 -0
  56. machwave/simulations/internal_ballistics.py +103 -0
  57. machwave/solvers/__init__.py +0 -0
  58. machwave/solvers/odes.py +60 -0
  59. machwave-0.1.0.dist-info/METADATA +746 -0
  60. machwave-0.1.0.dist-info/RECORD +61 -0
  61. machwave-0.1.0.dist-info/WHEEL +4 -0
File without changes
@@ -0,0 +1,87 @@
1
+ """
2
+ Atmospheric models for use in rocket simulations. The models are used to
3
+ calculate the properties of the atmosphere at a given altitude above mean sea
4
+ level (AMSL).
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+
9
+
10
+ class Atmosphere(ABC):
11
+ """Abstract class that represents an atmospheric model."""
12
+
13
+ @abstractmethod
14
+ def get_density(self, y_amsl: float) -> float:
15
+ """
16
+ Get the air density at the given altitude above mean sea level (AMSL).
17
+
18
+ Args:
19
+ y_amsl (float): Altitude above mean sea level in meters.
20
+
21
+ Returns:
22
+ float: Air density in kg/m^3.
23
+ """
24
+
25
+ @abstractmethod
26
+ def get_gravity(self, y_amsl: float) -> float:
27
+ """
28
+ Get the acceleration due to gravity at the given altitude above mean
29
+ sea level (AMSL).
30
+
31
+ Args:
32
+ y_amsl (float): Altitude above mean sea level in meters.
33
+
34
+ Returns:
35
+ float: Acceleration due to gravity in m/s^2.
36
+ """
37
+
38
+ @abstractmethod
39
+ def get_pressure(self, y_amsl: float) -> float:
40
+ """
41
+ Get the air pressure at the given altitude above mean sea level (AMSL).
42
+
43
+ Args:
44
+ y_amsl (float): Altitude above mean sea level in meters.
45
+
46
+ Returns:
47
+ float: Air pressure in Pascal (Pa).
48
+ """
49
+
50
+ @abstractmethod
51
+ def get_sonic_velocity(self, y_amsl: float) -> float:
52
+ """
53
+ Get the speed of sound in air at the given altitude above mean sea
54
+ level (AMSL).
55
+
56
+ Args:
57
+ y_amsl (float): Altitude above mean sea level in meters.
58
+
59
+ Returns:
60
+ float: Speed of sound in m/s.
61
+ """
62
+
63
+ @abstractmethod
64
+ def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
65
+ """
66
+ Get the wind velocity components at the given altitude above mean
67
+ sea level (AMSL).
68
+
69
+ Args:
70
+ y_amsl (float): Altitude above mean sea level in meters.
71
+
72
+ Returns:
73
+ tuple[float, float]: Wind velocity components (Northward, Eastward) in m/s.
74
+ """
75
+
76
+ @abstractmethod
77
+ def get_viscosity(self, y_amsl: float) -> float:
78
+ """
79
+ Get the dynamic viscosity of air at the given altitude above mean sea
80
+ level (AMSL).
81
+
82
+ Args:
83
+ y_amsl (float): Altitude above mean sea level in meters.
84
+
85
+ Returns:
86
+ float: Dynamic viscosity of air in Pascal-second (Pa-s).
87
+ """
@@ -0,0 +1,86 @@
1
+ """
2
+ Implementation of the 1976 Standard Atmosphere model.
3
+ """
4
+
5
+ from fluids.atmosphere import ATMOSPHERE_1976
6
+ import numpy as np
7
+
8
+ from machwave.models.atmosphere import Atmosphere
9
+
10
+
11
+ class Atmosphere1976(Atmosphere):
12
+ """
13
+ Atmospheric model based on the 1976 Standard Atmosphere. This model uses
14
+ the fluids library to calculate the properties of the atmosphere.
15
+ """
16
+
17
+ def get_density(self, y_amsl: float) -> float:
18
+ return ATMOSPHERE_1976(y_amsl).rho
19
+
20
+ def get_gravity(self, y_amsl: float) -> float:
21
+ return ATMOSPHERE_1976.gravity(y_amsl)
22
+
23
+ def get_pressure(self, y_amsl: float) -> float:
24
+ return ATMOSPHERE_1976(y_amsl).P
25
+
26
+ def get_sonic_velocity(self, y_amsl: float) -> float:
27
+ return ATMOSPHERE_1976(y_amsl).v_sonic
28
+
29
+ def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
30
+ """
31
+ 7 m/s wind velocity in both x and y directions.
32
+ """
33
+ return (7, 7)
34
+
35
+ def get_viscosity(self, y_amsl: float) -> float:
36
+ return ATMOSPHERE_1976(y_amsl).mu
37
+
38
+
39
+ class Atmosphere1976WindPowerLaw(Atmosphere1976):
40
+ """
41
+ Atmospheric model based on the 1976 Standard Atmosphere, using a power-law
42
+ model for wind velocity variation with altitude.
43
+ """
44
+
45
+ def __init__(self, v_ref: float, z_ref: float, alpha: float, direction_deg: float):
46
+ """
47
+ Initialize the atmosphere model with power-law wind parameters.
48
+
49
+ Args:
50
+ v_ref (float): Wind speed at the reference height (in m/s).
51
+ z_ref (float): Reference height (in meters) where the wind speed is known.
52
+ alpha (float): Wind shear exponent.
53
+ direction_deg (float): Wind direction in degrees (0° is North, 90° is East).
54
+ """
55
+ super().__init__()
56
+
57
+ if z_ref == 0:
58
+ raise ValueError("Please provide a non-zero reference height 'z_ref'.")
59
+
60
+ self.v_ref = v_ref
61
+ self.z_ref = z_ref
62
+ self.alpha = alpha
63
+ self.direction_deg = direction_deg
64
+
65
+ def get_wind_velocity(self, y_amsl: float) -> tuple[float, float]:
66
+ """
67
+ Get the wind velocity components at the given altitude above mean sea level (AMSL)
68
+ using the power law.
69
+
70
+ Args:
71
+ y_amsl (float): Altitude above mean sea level in meters.
72
+
73
+ Returns:
74
+ tuple[float, float]: Wind velocity components (Northward, Eastward) in m/s.
75
+ """
76
+ if y_amsl <= 0:
77
+ y_amsl = self.z_ref
78
+
79
+ wind_speed = self.v_ref * (y_amsl / self.z_ref) ** self.alpha
80
+
81
+ direction_rad = np.radians(self.direction_deg)
82
+
83
+ v_northward = wind_speed * np.cos(direction_rad)
84
+ v_eastward = wind_speed * np.sin(direction_rad)
85
+
86
+ return v_northward, v_eastward
@@ -0,0 +1,37 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class Material:
6
+ """
7
+ Base class representing a generic material.
8
+
9
+ Attributes:
10
+ density (float): Density of the material.
11
+ yield_strength (float): Yield strength of the material.
12
+ ultimate_strength (float): Ultimate strength of the material.
13
+ """
14
+
15
+ density: float
16
+ yield_strength: float
17
+ ultimate_strength: float
18
+
19
+
20
+ @dataclass
21
+ class NozzleMaterial(Material):
22
+ """
23
+ Base class for a Nozzle material.
24
+
25
+ Contains all attributes from the Material class, adding c_1 and c_2 for
26
+ calculating isentropic flow correction factors. These special parameters
27
+ are referenced in the a015140 paper.
28
+
29
+ Attributes:
30
+ c_1 (float): Coefficient related to heat transfer properties of a BATES
31
+ motor.
32
+ c_2 (float): Time constant obtained from the analysis of the transient
33
+ heating of a standard BATES motor.
34
+ """
35
+
36
+ c_1: float
37
+ c_2: float
@@ -0,0 +1,86 @@
1
+ from dataclasses import dataclass
2
+
3
+ from . import NozzleMaterial
4
+
5
+
6
+ @dataclass
7
+ class Steel(NozzleMaterial):
8
+ """
9
+ Steel material class derived from the NozzleMaterial base class.
10
+
11
+ This class represents a specific type of material, Steel, which inherits
12
+ properties from the NozzleMaterial base class. It provides default values
13
+ for the density, yield strength, ultimate strength, c_1, and c_2 specific to
14
+ Steel.
15
+
16
+ Data obtained from:
17
+ https://www.thyssenkrupp-materials.co.uk/stainless-steel-304-14301.html
18
+
19
+ Inherits:
20
+ NozzleMaterial: Base class representing a nozzle material.
21
+
22
+ Attributes:
23
+ None
24
+ """
25
+
26
+ density: float = 8000
27
+ yield_strength: float = 210e6
28
+ ultimate_strength: float = 520e6
29
+ c_1: float = 0.00506
30
+ c_2: float = 0.0
31
+
32
+
33
+ @dataclass
34
+ class Al6063T5(NozzleMaterial):
35
+ """
36
+ Al6063T5 (Aluminum) material class derived from the NozzleMaterial base
37
+ class.
38
+
39
+ This class represents a specific type of material, Al6063T5 (Aluminum),
40
+ which inherits properties from the NozzleMaterial base class. It provides
41
+ default values for the density, yield strength, ultimate strength, c_1, and
42
+ c_2 specific to Al6063T5.
43
+
44
+ Data obtained from:
45
+ https://www.makeitfrom.com/material-properties/6063-T5-Aluminum
46
+
47
+ Inherits:
48
+ NozzleMaterial: Base class representing a nozzle material.
49
+
50
+ Attributes:
51
+ None
52
+ """
53
+
54
+ density: float = 2700
55
+ yield_strength: float = 145e6
56
+ ultimate_strength: float = 185e6
57
+ c_1: float = 0.00506
58
+ c_2: float = 0.0
59
+
60
+
61
+ @dataclass
62
+ class Al6061T6(NozzleMaterial):
63
+ """
64
+ Al6061T6 (Aluminum) material class derived from the NozzleMaterial base
65
+ class.
66
+
67
+ This class represents a specific type of material, Al6061T6 (Aluminum),
68
+ which inherits properties from the NozzleMaterial base class. It provides
69
+ default values for the density, yield strength, ultimate strength, c_1, and
70
+ c_2 specific to Al6061T6.
71
+
72
+ Data obtained from:
73
+ https://matweb.com/search/DataSheet.aspx?MatGUID=b8d536e0b9b54bd7b69e4124d8f1d20a&ckck=1
74
+
75
+ Inherits:
76
+ NozzleMaterial: Base class representing a nozzle material.
77
+
78
+ Attributes:
79
+ None
80
+ """
81
+
82
+ density: float = 2700
83
+ yield_strength: float = 262e6
84
+ ultimate_strength: float = 290e6
85
+ c_1: float = 0.00506
86
+ c_2: float = 0.0
@@ -0,0 +1,50 @@
1
+ from dataclasses import dataclass
2
+
3
+ from . import Material
4
+
5
+
6
+ @dataclass
7
+ class EPDM(Material):
8
+ """
9
+ EPDM (Ethylene Propylene Diene Monomer) material class.
10
+
11
+ Data obtained from:
12
+ https://www.matweb.com/search/datasheet.aspx?matguid=f8e3355cc2c541fbb0174960466819c0&ckck=1
13
+
14
+ Inherits:
15
+ Material: Base class representing a generic material.
16
+
17
+ Attributes:
18
+ None
19
+ """
20
+
21
+ density: float = 1500
22
+ yield_strength: float = None
23
+ ultimate_strength: float = 17e6
24
+
25
+
26
+ class EpoxiResin(Material):
27
+ """
28
+ EpoxiResin material class.
29
+
30
+ Inherits:
31
+ Material: Base class representing a generic material.
32
+
33
+ Attributes:
34
+ None
35
+ """
36
+
37
+ def __init__(self) -> None:
38
+ """
39
+ Initialize an EpoxiResin object.
40
+
41
+ This constructor sets the default values for the density, yield
42
+ strength, and ultimate strength of EpoxiResin.
43
+
44
+ Args:
45
+ None
46
+
47
+ Returns:
48
+ None
49
+ """
50
+ super().__init__(density=1100, yield_strength=60e6, ultimate_strength=60e6)
@@ -0,0 +1,209 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ import numpy as np
4
+
5
+ from machwave.models.propulsion.grain import Grain
6
+ from machwave.models.propulsion.propellants import Propellant
7
+ from machwave.models.propulsion.structure import MotorStructure
8
+ from machwave.services.isentropic_flow import (
9
+ get_thrust_coefficients,
10
+ get_thrust_from_cf,
11
+ )
12
+
13
+
14
+ class Motor(ABC):
15
+ """
16
+ Abstract rocket motor/engine class. Can be used to model any chemical
17
+ rocket propulsion system, such as Solid, Hybrid and Liquid.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ propellant: Propellant,
23
+ structure: MotorStructure,
24
+ ) -> None:
25
+ """
26
+ Instantiates object attributes common to any motor/engine (Solid,
27
+ Hybrid or Liquid).
28
+
29
+ Args:
30
+ propellant (Propellant): Object representing the propellant used in the motor.
31
+ structure (MotorStructure): Object representing the structure of the motor.
32
+ """
33
+ self.propellant = propellant
34
+ self.structure = structure
35
+
36
+ @abstractmethod
37
+ def get_launch_mass(self) -> float:
38
+ """
39
+ Calculates the total mass of the rocket before launch.
40
+
41
+ Returns:
42
+ float: Total mass of the rocket before launch, in kg
43
+ """
44
+ pass
45
+
46
+ @abstractmethod
47
+ def get_dry_mass(self) -> float:
48
+ """
49
+ Calculates the dry mass of the rocket at any time.
50
+
51
+ Returns:
52
+ float: Dry mass of the rocket, in kg
53
+ """
54
+ pass
55
+
56
+ @abstractmethod
57
+ def get_center_of_gravity(self) -> np.ndarray:
58
+ """
59
+ Calculates center of gravity of the propulsion system.
60
+
61
+ Coordinate system is originated in the point defined by the nozzle's
62
+ exit area surface and the combustion chamber axis.
63
+
64
+ Returns:
65
+ np.ndarray: Center of gravity position, in m, [x, y, z]
66
+ """
67
+ pass
68
+
69
+ @abstractmethod
70
+ def get_thrust_coefficient_correction_factor(self) -> float:
71
+ """
72
+ Calculates the thrust coefficient correction factor. This factor is
73
+ adimensional and should be applied to the ideal thrust coefficient to
74
+ get the real thrust coefficient.
75
+
76
+ Returns:
77
+ float: Thrust coefficient correction factor
78
+ """
79
+ pass
80
+
81
+ @abstractmethod
82
+ def get_thrust_coefficient(self) -> float:
83
+ """
84
+ Calculates the thrust coefficient at a particular instant.
85
+
86
+ Returns:
87
+ float: Thrust coefficient
88
+ """
89
+ pass
90
+
91
+ def get_thrust(self, cf: float, chamber_pressure: float) -> float:
92
+ """
93
+ Calculates the thrust based on instantaneous thrust coefficient and
94
+ chamber pressure.
95
+
96
+ Utilized nozzle throat area from the structure and nozzle classes.
97
+
98
+ Args:
99
+ cf (float): Instantaneous thrust coefficient, adimensional
100
+ chamber_pressure (float): Instantaneous chamber pressure, in Pa
101
+
102
+ Returns:
103
+ float: Instantaneous thrust, in Newtons
104
+ """
105
+ return get_thrust_from_cf(
106
+ cf,
107
+ chamber_pressure,
108
+ self.structure.nozzle.get_throat_area(),
109
+ )
110
+
111
+
112
+ class SolidMotor(Motor):
113
+ def __init__(
114
+ self,
115
+ grain: Grain,
116
+ propellant: Propellant,
117
+ structure: MotorStructure,
118
+ ) -> None:
119
+ self.grain = grain
120
+ super().__init__(propellant, structure)
121
+
122
+ self.cf_ideal = None # ideal thrust coefficient
123
+ self.cf_real = None # real thrust coefficient
124
+
125
+ def get_free_chamber_volume(self, propellant_volume: float) -> float:
126
+ """
127
+ Calculates the chamber volume without any propellant.
128
+
129
+ Args:
130
+ propellant_volume (float): Propellant volume, in m^3
131
+
132
+ Returns:
133
+ float: Free chamber volume, in m^3
134
+ """
135
+ return self.structure.chamber.empty_volume - propellant_volume
136
+
137
+ @property
138
+ def initial_propellant_mass(self) -> float:
139
+ """
140
+ Returns:
141
+ float: Initial propellant mass, in kg
142
+ """
143
+ return (
144
+ self.grain.get_propellant_volume(web_distance=0) * self.propellant.density
145
+ )
146
+
147
+ def get_thrust_coefficient_correction_factor(
148
+ self, n_kin: float, n_bl: float, n_tp: float
149
+ ) -> float:
150
+ """
151
+ Args:
152
+ n_kin (float): Kinematic correction factor, adimensional
153
+ n_bl (float): Boundary layer correction factor, adimensional
154
+ n_tp (float): Two-phase correction factor, adimensional
155
+
156
+ Returns:
157
+ float: Thrust coefficient correction factor, adimensional
158
+ """
159
+ return (
160
+ (100 - (n_kin + n_bl + n_tp))
161
+ * self.structure.nozzle.get_divergent_correction_factor()
162
+ / 100
163
+ * self.propellant.combustion_efficiency
164
+ )
165
+
166
+ def get_thrust_coefficient(
167
+ self,
168
+ chamber_pressure: float,
169
+ exit_pressure: float,
170
+ external_pressure: float,
171
+ expansion_ratio: float,
172
+ k_2ph_ex: float,
173
+ n_cf: float,
174
+ ) -> float:
175
+ """
176
+ Args:
177
+ chamber_pressure (float): Chamber pressure, in Pa
178
+ exit_pressure (float): Exit pressure, in Pa
179
+ external_pressure (float): External pressure, in Pa
180
+ expansion_ratio (float): Expansion ratio, adimensional
181
+ k_2ph_ex (float): Two-phase isentropic coefficient, adimensional
182
+ n_cf (float): Thrust coefficient correction factor, adimensional
183
+
184
+ Returns:
185
+ float: Instanteneous thrust coefficient, adimensional
186
+ """
187
+ self.cf_ideal, self.cf_real = get_thrust_coefficients(
188
+ chamber_pressure,
189
+ exit_pressure,
190
+ external_pressure,
191
+ expansion_ratio,
192
+ k_2ph_ex,
193
+ n_cf,
194
+ )
195
+ return self.cf_real
196
+
197
+ def get_launch_mass(self) -> float:
198
+ return self.structure.dry_mass + self.initial_propellant_mass
199
+
200
+ def get_dry_mass(self) -> float:
201
+ return self.structure.dry_mass
202
+
203
+ def get_center_of_gravity(self) -> np.ndarray:
204
+ """
205
+ Constant CG throughout the operation. Half the chamber length.
206
+
207
+ TODO: implement grain CG calculation.
208
+ """
209
+ return np.array([self.structure.chamber.length / 2, 0, 0])