6
6
7
7
extern crate libm;
8
8
9
+ use log:: debug;
9
10
use serde:: Deserialize ;
10
11
use std:: f32:: consts:: PI ;
11
12
use std:: fmt;
12
13
13
14
use super :: gas;
14
15
16
+ #[ derive( Copy , Clone ) ]
15
17
pub struct Balloon {
16
- pub intact : bool , // whether or not it has burst
17
- pub mass : f32 , // balloon mass (kg)
18
- pub temperature : f32 , // fail if surface temperature exceeds this (K)
19
- pub volume : f32 , // internal volume of the balloon (m^3)
20
- pub drag_coeff : f32 , // drag coefficient
21
- pub lift_gas : gas:: GasVolume , // gas inside the balloon
22
- material : Material , // what the balloon is made of
23
- initial_volume : f32 , // internal volume (m^3) at zero pressure
24
- skin_thickness : f32 , // thickness of the skin of the balloon (m)
18
+ pub intact : bool , // whether or not it has burst
19
+ pub mass : f32 , // balloon mass (kg)
20
+ pub temperature : f32 , // fail if surface temperature exceeds this (K)
21
+ pub drag_coeff : f32 , // drag coefficient
22
+ pub lift_gas : gas:: GasVolume , // gas inside the balloon
23
+ pub material : Material , // what the balloon is made of
24
+ pub skin_thickness : f32 , // thickness of the skin of the balloon (m)
25
+ unstretched_thickness : f32 , // thickness of the skin of the balloon without stretch (m)
26
+ unstretched_radius : f32 , // radius of balloon without stretch (m)
27
+ stress : f32 ,
28
+ strain : f32 ,
25
29
}
26
30
27
31
impl Balloon {
28
32
pub fn new (
29
- material : Material , // material of balloon skin
30
- skin_thickness : f32 , // balloon skin thickness (m) at zero pressure
33
+ material : Material , // material of balloon skin
34
+ skin_thickness : f32 , // balloon skin thickness (m) at zero pressure
31
35
barely_inflated_diameter : f32 , // internal diameter (m) at zero pressure
32
36
lift_gas : gas:: GasVolume , // species of gas inside balloon
33
37
) -> Self {
34
- let initial_radius = barely_inflated_diameter / 2.0 ;
35
- let initial_volume = spherical_volume ( initial_radius) ;
36
- let mass = shell_volume ( initial_radius, skin_thickness) * material. density ;
38
+ let unstretched_radius = barely_inflated_diameter / 2.0 ;
39
+ let mass = shell_volume ( unstretched_radius, skin_thickness) * material. density ;
37
40
Balloon {
38
41
intact : true ,
39
42
mass,
40
43
temperature : 293.0 ,
41
- volume : initial_volume,
42
44
drag_coeff : 0.3 ,
43
45
lift_gas,
44
46
material,
45
- initial_volume,
46
47
skin_thickness,
48
+ unstretched_thickness : skin_thickness,
49
+ unstretched_radius,
50
+ stress : 0.0 ,
51
+ strain : 1.0 ,
47
52
}
48
53
}
49
54
55
+ pub fn surface_area ( self ) -> f32 {
56
+ sphere_surface_area ( sphere_radius_from_volume ( self . lift_gas . volume ( ) ) )
57
+ }
58
+
59
+ pub fn radius ( self ) -> f32 {
60
+ sphere_radius_from_volume ( self . volume ( ) )
61
+ }
62
+
63
+ pub fn volume ( self ) -> f32 {
64
+ self . lift_gas . volume ( )
65
+ }
66
+
67
+ fn set_volume ( & mut self , new_volume : f32 ) {
68
+ self . lift_gas . set_volume ( new_volume)
69
+ }
70
+
71
+ pub fn pressure ( & mut self ) -> f32 {
72
+ self . lift_gas . pressure ( )
73
+ }
74
+
75
+ fn set_pressure ( & mut self , new_pressure : f32 ) {
76
+ self . lift_gas . set_pressure ( new_pressure)
77
+ }
78
+
79
+ fn set_thickness ( & mut self , new_thickness : f32 ) {
80
+ self . skin_thickness = new_thickness
81
+ }
82
+
83
+ fn gage_pressure ( self , external_pressure : f32 ) -> f32 {
84
+ self . lift_gas . pressure ( ) - external_pressure
85
+ }
86
+
87
+ pub fn stress ( self ) -> f32 {
88
+ self . stress
89
+ }
90
+
91
+ fn set_stress ( & mut self , external_pressure : f32 ) {
92
+ // hoop stress (Pa) of thin-walled hollow sphere from internal pressure
93
+ // https://en.wikipedia.org/wiki/Pressure_vessel#Stress_in_thin-walled_pressure_vessels
94
+ // https://pkel015.connect.amazon.auckland.ac.nz/SolidMechanicsBooks/Part_I/BookSM_Part_I/07_ElasticityApplications/07_Elasticity_Applications_03_Presure_Vessels.pdf
95
+ self . stress = self . gage_pressure ( external_pressure) * self . radius ( ) / ( 2.0 * self . skin_thickness ) ;
96
+ if self . stress > self . material . max_stress {
97
+ self . burst ( format ! (
98
+ "Hoop stress ({:?} Pa) exceeded maximum stress ({:?} Pa)" ,
99
+ self . stress, self . material. max_stress
100
+ ) ) ;
101
+ }
102
+ }
103
+
104
+ pub fn strain ( self ) -> f32 {
105
+ self . strain
106
+ }
107
+
108
+ fn set_strain ( & mut self ) {
109
+ // strain (%) of thin-walled hollow sphere from internal pressure
110
+ // https://en.wikipedia.org/wiki/Pressure_vessel#Stress_in_thin-walled_pressure_vessels
111
+ // https://pkel015.connect.amazon.auckland.ac.nz/SolidMechanicsBooks/Part_I/BookSM_Part_I/07_ElasticityApplications/07_Elasticity_Applications_03_Presure_Vessels.pdf
112
+ self . strain = self . radius ( ) / self . unstretched_radius ;
113
+ if self . strain > self . material . max_strain {
114
+ self . burst ( format ! (
115
+ "Tangential strain ({:?} %) exceeded maximum strain ({:?} %)" ,
116
+ self . strain * 100.0 ,
117
+ self . material. max_strain * 100.0
118
+ ) ) ;
119
+ }
120
+ }
121
+
122
+ fn radial_displacement ( self , external_pressure : f32 ) -> f32 {
123
+ // https://pkel015.connect.amazon.auckland.ac.nz/SolidMechanicsBooks/Part_I/BookSM_Part_I/07_ElasticityApplications/07_Elasticity_Applications_03_Presure_Vessels.pdf
124
+ ( ( 1.0 - self . material . poissons_ratio ) / self . material . elasticity )
125
+ * ( ( self . gage_pressure ( external_pressure) * libm:: powf ( self . radius ( ) , 2.0 ) ) / 2.0
126
+ * self . skin_thickness )
127
+ }
128
+
129
+ fn rebound ( & mut self , radial_displacement : f32 ) -> f32 {
130
+ // https://physics.stackexchange.com/questions/10372/inflating-a-balloon-expansion-resistance
131
+ self . set_thickness (
132
+ self . unstretched_thickness * libm:: powf ( self . unstretched_radius / self . radius ( ) , 2.0 ) ,
133
+ ) ;
134
+ 2.0 * self . material . elasticity
135
+ * radial_displacement
136
+ * self . unstretched_thickness
137
+ * self . unstretched_radius
138
+ / libm:: powf ( self . radius ( ) , 3.0 )
139
+ }
140
+
50
141
pub fn stretch ( & mut self , external_pressure : f32 ) {
51
142
// stretch the balloon and/or compress the gas inside.
52
143
// - the gas wants to be at the same pressure as ambient
@@ -57,59 +148,58 @@ impl Balloon {
57
148
// - the balloon fails when it starts to plasticly deform, in other
58
149
// words the balloon stretches as long as tangential stress is less
59
150
// than the material's yield stress
151
+ debug ! (
152
+ "current gage pressure: {:?}" ,
153
+ self . gage_pressure( external_pressure)
154
+ ) ;
155
+
156
+ self . set_stress ( external_pressure) ;
157
+ self . set_strain ( ) ;
60
158
61
- let mut equilibrium_gas = self . lift_gas . clone ( ) ;
62
- equilibrium_gas . set_pressure ( external_pressure) ;
63
-
64
- // percent elongation aka tangential strain (m/m)
65
- let original_radius = sphere_radius_from_volume ( self . initial_volume ) ;
66
- let equilibrium_radius = sphere_radius_from_volume ( equilibrium_gas . volume ( ) ) ;
67
- let elongation = ( equilibrium_radius - original_radius ) / original_radius ;
68
- if elongation < self . material . max_elongation {
69
- self . volume = self . lift_gas . volume ( ) ;
70
- self . lift_gas . set_pressure ( external_pressure ) ;
71
- } else {
72
- self . burst ( )
73
- // self.volume = spherical_volume(original_radius * self.material.max_elongation);
74
- // self.lift_gas.set_volume(self.volume );
159
+ if self . intact {
160
+ let delta_r = self . radial_displacement ( external_pressure) ;
161
+ debug ! (
162
+ "radius before stretch: {:?} delta_r: {:?}" ,
163
+ self . radius ( ) ,
164
+ delta_r
165
+ ) ;
166
+ let internal_pressure = self . rebound ( delta_r ) ;
167
+ self . set_pressure ( internal_pressure + external_pressure ) ;
168
+ debug ! ( "radius after stretch: {:?}" , self . radius ( ) ) ;
169
+ debug ! (
170
+ "gage pressure after stretch: {:?}" ,
171
+ self . gage_pressure ( external_pressure )
172
+ ) ;
75
173
}
76
- // let stress = tangential_stress(
77
- // self.lift_gas.pressure() - external_pressure,
78
- // self.volume,
79
- // self.balloon_thickness,
80
- // );
81
- // if stress > self.material.max_stress
82
- // {
83
- // self.burst();
84
- // }
85
- }
86
-
87
- fn burst ( & mut self ) {
174
+
175
+ }
176
+
177
+ fn burst ( & mut self , reason : String ) {
88
178
// Assert new balloon attributes to reflect that it has burst
89
179
self . intact = false ;
90
- self . volume = 0.0 ;
180
+ self . set_volume ( 0.0 ) ;
91
181
self . lift_gas . set_mass ( 0.0 ) ;
182
+ log:: warn!( "The balloon has burst! Reason: {:?}" , reason)
92
183
}
93
184
}
94
185
95
- fn spherical_volume ( radius : f32 ) -> f32 {
186
+ fn sphere_volume ( radius : f32 ) -> f32 {
96
187
( 4.0 / 3.0 ) * PI * libm:: powf ( radius, 3.0 )
97
188
}
98
189
99
190
fn shell_volume ( internal_radius : f32 , thickness : f32 ) -> f32 {
100
191
let external_radius = internal_radius + thickness;
101
- let internal_volume = spherical_volume ( internal_radius) ;
102
- let external_volume = spherical_volume ( external_radius) ;
192
+ let internal_volume = sphere_volume ( internal_radius) ;
193
+ let external_volume = sphere_volume ( external_radius) ;
103
194
external_volume - internal_volume
104
195
}
105
196
106
197
fn sphere_radius_from_volume ( volume : f32 ) -> f32 {
107
198
libm:: powf ( volume, 1.0 / 3.0 ) / ( 4.0 / 3.0 ) * PI
108
199
}
109
200
110
- fn tangential_stress ( pressure_difference : f32 , internal_volume : f32 , shell_thickness : f32 ) -> f32 {
111
- // tangential stress (Pa) of hollow sphere from internal pressure
112
- pressure_difference * sphere_radius_from_volume ( internal_volume) / ( 2.0 * shell_thickness)
201
+ fn sphere_surface_area ( radius : f32 ) -> f32 {
202
+ 4.0 * PI * libm:: powf ( radius, 2.0 )
113
203
}
114
204
115
205
// ----------------------------------------------------------------------------
@@ -119,22 +209,26 @@ fn tangential_stress(pressure_difference: f32, internal_volume: f32, shell_thick
119
209
// Source: https://www.matweb.com/
120
210
// ----------------------------------------------------------------------------
121
211
122
- #[ derive( Clone , PartialEq ) ]
212
+ #[ derive( Copy , Clone , PartialEq ) ]
123
213
pub struct Material {
124
214
pub max_temperature : f32 , // temperature (K) where the given material fails
125
- pub density : f32 , // density (kg/m^3)
126
- pub emissivity : f32 , // emissivity coefficient of the material for blackbody light
215
+ pub density : f32 , // density (kg/m^3)
216
+ pub emissivity : f32 , // how much thermal radiation is emitted
217
+ pub absorptivity : f32 , // how much thermal radiation is absorbed
127
218
pub thermal_conductivity : f32 , // thermal conductivity (W/mK) of the material at room temperature
128
- pub max_elongation : f32 , // elongation at failure (decimal, unitless) 1 = original size
129
- pub max_stress : f32 , // tangential stress at failure (Pa)
219
+ pub specific_heat : f32 , // J/kgK
220
+ pub poissons_ratio : f32 , // ratio of change in width for a given change in length
221
+ pub elasticity : f32 , // Youngs Modulus aka Modulus of Elasticity (Pa)
222
+ pub max_strain : f32 , // elongation at failure (decimal, unitless) 1 = original size
223
+ pub max_stress : f32 , // tangential stress at failure (Pa)
130
224
}
131
225
132
226
impl Material {
133
227
pub fn new ( material_type : MaterialType ) -> Self {
134
228
match material_type {
135
229
MaterialType :: Rubber => RUBBER ,
136
- MaterialType :: LowDensityPolyethylene => LOW_DENSITY_POLYETHYLENE ,
137
- _ => NOTHING
230
+ MaterialType :: LDPE | MaterialType :: LowDensityPolyethylene => LOW_DENSITY_POLYETHYLENE ,
231
+ _ => NOTHING ,
138
232
}
139
233
}
140
234
}
@@ -144,6 +238,7 @@ pub enum MaterialType {
144
238
// Species of gas with a known molar mass (kg/mol)
145
239
Nothing ,
146
240
Rubber ,
241
+ LDPE ,
147
242
LowDensityPolyethylene ,
148
243
}
149
244
@@ -152,7 +247,9 @@ impl fmt::Display for MaterialType {
152
247
match * self {
153
248
MaterialType :: Nothing => write ! ( f, "nothing" ) ,
154
249
MaterialType :: Rubber => write ! ( f, "rubber" ) ,
155
- MaterialType :: LowDensityPolyethylene => write ! ( f, "low-density polyethylene (LDPE)" ) ,
250
+ MaterialType :: LDPE | MaterialType :: LowDensityPolyethylene => {
251
+ write ! ( f, "low-density polyethylene (LDPE)" )
252
+ }
156
253
}
157
254
}
158
255
}
@@ -162,27 +259,42 @@ pub const NOTHING: Material = Material {
162
259
max_temperature : f32:: INFINITY ,
163
260
density : 0.0 ,
164
261
emissivity : 1.0 ,
262
+ absorptivity : 0.0 ,
165
263
thermal_conductivity : f32:: INFINITY ,
166
- max_elongation : f32:: INFINITY ,
264
+ specific_heat : 0.0 ,
265
+ poissons_ratio : 0.5 ,
266
+ elasticity : f32:: INFINITY ,
267
+ max_strain : f32:: INFINITY ,
167
268
max_stress : f32:: INFINITY ,
168
269
} ;
169
270
170
271
pub const RUBBER : Material = Material {
171
- // Natural Rubber, Vulcanized (NR, IR, Polyisoprene)
172
- max_temperature : 400.0 ,
173
- density : 950.0 ,
272
+ // Nitrile Butadiene Rubber
273
+ // https://designerdata.nl/materials/plastics/rubbers/nitrile-butadiene-rubber
274
+ max_temperature : 385.0 ,
275
+ density : 1000.0 ,
174
276
emissivity : 0.86 ,
175
- thermal_conductivity : 0.34 ,
176
- max_elongation : 8.0 ,
177
- max_stress : 150_000_000.0 ,
277
+ absorptivity : 0.86 ,
278
+ thermal_conductivity : 0.25 ,
279
+ specific_heat : 1490.0 ,
280
+ poissons_ratio : 0.5 ,
281
+ elasticity : 4_000_000.0 ,
282
+ // max_strain: 8.0,
283
+ max_strain : 8.0 ,
284
+ max_stress : 25_000_000.0 ,
178
285
} ;
179
286
180
287
pub const LOW_DENSITY_POLYETHYLENE : Material = Material {
181
- // Low Density Polyethylene (LDPE), Film Grade
182
- max_temperature : 380.0 ,
183
- density : 910.0 ,
288
+ // Low Density Polyethylene (LDPE)
289
+ // https://designerdata.nl/materials/plastics/thermo-plastics/low-density-polyethylene
290
+ max_temperature : 348.0 ,
291
+ density : 919.0 ,
184
292
emissivity : 0.94 ,
185
- thermal_conductivity : 0.15 ,
186
- max_elongation : 1.0 ,
187
- max_stress : 300_000_000.0 ,
188
- } ;
293
+ absorptivity : 0.94 ,
294
+ thermal_conductivity : 0.3175 ,
295
+ specific_heat : 2600.0 ,
296
+ poissons_ratio : 0.5 ,
297
+ elasticity : 300_000_000.0 ,
298
+ max_strain : 6.25 ,
299
+ max_stress : 10_000_000.0 ,
300
+ } ;
0 commit comments