@@ -193,6 +193,9 @@ class SolidMotor(Motor):
193193 SolidMotor.reference_pressure : int, float
194194 Atmospheric pressure in Pa at which the thrust data was recorded.
195195 It will allow to obtain the net thrust in the Flight class.
196+ SolidMotor.only_radial_burn : bool
197+ If True, grain regression is restricted to radial burn only (inner radius growth).
198+ Grain length remains constant throughout the burn. Default is False.
196199 """
197200
198201 # pylint: disable=too-many-arguments
@@ -217,6 +220,7 @@ def __init__(
217220 interpolation_method = "linear" ,
218221 coordinate_system_orientation = "nozzle_to_combustion_chamber" ,
219222 reference_pressure = None ,
223+ only_radial_burn = False ,
220224 ):
221225 """Initialize Motor class, process thrust curve and geometrical
222226 parameters and store results.
@@ -314,6 +318,11 @@ class Function. Thrust units are Newtons.
314318 "nozzle_to_combustion_chamber".
315319 reference_pressure : int, float, optional
316320 Atmospheric pressure in Pa at which the thrust data was recorded.
321+ only_radial_burn : boolean, optional
322+ If True, inhibits the grain from burning axially, only computing
323+ radial burn. If False, allows the grain to also burn
324+ axially. May be useful for axially inhibited grains or hybrid motors.
325+ Default is False.
317326
318327 Returns
319328 -------
@@ -331,6 +340,7 @@ class Function. Thrust units are Newtons.
331340 interpolation_method = interpolation_method ,
332341 coordinate_system_orientation = coordinate_system_orientation ,
333342 reference_pressure = reference_pressure ,
343+ only_radial_burn = only_radial_burn ,
334344 )
335345 # Nozzle parameters
336346 self .throat_radius = throat_radius
@@ -353,6 +363,9 @@ class Function. Thrust units are Newtons.
353363 )
354364 self .grain_initial_mass = self .grain_density * self .grain_initial_volume
355365
366+ # Burn surface definition
367+ self .only_radial_burn = only_radial_burn
368+
356369 self .evaluate_geometry ()
357370
358371 # Initialize plots and prints object
@@ -500,17 +513,25 @@ def geometry_dot(t, y):
500513
501514 # Compute state vector derivative
502515 grain_inner_radius , grain_height = y
503- burn_area = (
504- 2
505- * np .pi
506- * (
507- grain_outer_radius ** 2
508- - grain_inner_radius ** 2
509- + grain_inner_radius * grain_height
516+ if self .only_radial_burn :
517+ burn_area = 2 * np .pi * (grain_inner_radius * grain_height )
518+
519+ grain_inner_radius_derivative = - volume_diff / burn_area
520+ grain_height_derivative = 0 # Set to zero to disable axial burning
521+
522+ else :
523+ burn_area = (
524+ 2
525+ * np .pi
526+ * (
527+ grain_outer_radius ** 2
528+ - grain_inner_radius ** 2
529+ + grain_inner_radius * grain_height
530+ )
510531 )
511- )
512- grain_inner_radius_derivative = - volume_diff / burn_area
513- grain_height_derivative = - 2 * grain_inner_radius_derivative
532+
533+ grain_inner_radius_derivative = - volume_diff / burn_area
534+ grain_height_derivative = - 2 * grain_inner_radius_derivative
514535
515536 return [grain_inner_radius_derivative , grain_height_derivative ]
516537
@@ -521,32 +542,55 @@ def geometry_jacobian(t, y):
521542
522543 # Compute jacobian
523544 grain_inner_radius , grain_height = y
524- factor = volume_diff / (
525- 2
526- * np .pi
527- * (
528- grain_outer_radius ** 2
529- - grain_inner_radius ** 2
530- + grain_inner_radius * grain_height
545+ if self .only_radial_burn :
546+ factor = volume_diff / (
547+ 2 * np .pi * (grain_inner_radius * grain_height ) ** 2
531548 )
532- ** 2
533- )
534- inner_radius_derivative_wrt_inner_radius = factor * (
535- grain_height - 2 * grain_inner_radius
536- )
537- inner_radius_derivative_wrt_height = factor * grain_inner_radius
538- height_derivative_wrt_inner_radius = (
539- - 2 * inner_radius_derivative_wrt_inner_radius
540- )
541- height_derivative_wrt_height = - 2 * inner_radius_derivative_wrt_height
542549
543- return [
544- [
545- inner_radius_derivative_wrt_inner_radius ,
546- inner_radius_derivative_wrt_height ,
547- ],
548- [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
549- ]
550+ inner_radius_derivative_wrt_inner_radius = factor * (
551+ grain_height - 2 * grain_inner_radius
552+ )
553+ inner_radius_derivative_wrt_height = 0
554+ height_derivative_wrt_inner_radius = 0
555+ height_derivative_wrt_height = 0
556+ # Height is a constant, so all the derivatives with respect to it are set to zero
557+
558+ return [
559+ [
560+ inner_radius_derivative_wrt_inner_radius ,
561+ inner_radius_derivative_wrt_height ,
562+ ],
563+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
564+ ]
565+
566+ else :
567+ factor = volume_diff / (
568+ 2
569+ * np .pi
570+ * (
571+ grain_outer_radius ** 2
572+ - grain_inner_radius ** 2
573+ + grain_inner_radius * grain_height
574+ )
575+ ** 2
576+ )
577+
578+ inner_radius_derivative_wrt_inner_radius = factor * (
579+ grain_height - 2 * grain_inner_radius
580+ )
581+ inner_radius_derivative_wrt_height = factor * grain_inner_radius
582+ height_derivative_wrt_inner_radius = (
583+ - 2 * inner_radius_derivative_wrt_inner_radius
584+ )
585+ height_derivative_wrt_height = - 2 * inner_radius_derivative_wrt_height
586+
587+ return [
588+ [
589+ inner_radius_derivative_wrt_inner_radius ,
590+ inner_radius_derivative_wrt_height ,
591+ ],
592+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
593+ ]
550594
551595 def terminate_burn (t , y ): # pylint: disable=unused-argument
552596 end_function = (self .grain_outer_radius - y [0 ]) * y [1 ]
@@ -597,16 +641,24 @@ def burn_area(self):
597641 burn_area : Function
598642 Function representing the burn area progression with the time.
599643 """
600- burn_area = (
601- 2
602- * np .pi
603- * (
604- self .grain_outer_radius ** 2
605- - self .grain_inner_radius ** 2
606- + self .grain_inner_radius * self .grain_height
644+ if self .only_radial_burn :
645+ burn_area = (
646+ 2
647+ * np .pi
648+ * (self .grain_inner_radius * self .grain_height )
649+ * self .grain_number
650+ )
651+ else :
652+ burn_area = (
653+ 2
654+ * np .pi
655+ * (
656+ self .grain_outer_radius ** 2
657+ - self .grain_inner_radius ** 2
658+ + self .grain_inner_radius * self .grain_height
659+ )
660+ * self .grain_number
607661 )
608- * self .grain_number
609- )
610662 return burn_area
611663
612664 @funcify_method ("Time (s)" , "burn rate (m/s)" )
@@ -778,6 +830,7 @@ def to_dict(self, **kwargs):
778830 "grain_initial_height" : self .grain_initial_height ,
779831 "grain_separation" : self .grain_separation ,
780832 "grains_center_of_mass_position" : self .grains_center_of_mass_position ,
833+ "only_radial_burn" : self .only_radial_burn ,
781834 }
782835 )
783836
@@ -827,4 +880,5 @@ def from_dict(cls, data):
827880 interpolation_method = data ["interpolate" ],
828881 coordinate_system_orientation = data ["coordinate_system_orientation" ],
829882 reference_pressure = data .get ("reference_pressure" ),
883+ only_radial_burn = data .get ("only_radial_burn" , False ),
830884 )
0 commit comments