@@ -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,11 +318,19 @@ 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 -------
320329 None
321330 """
331+ # Store before calling super().__init__() since it calls evaluate_geometry()
332+ self .only_radial_burn = only_radial_burn
333+
322334 super ().__init__ (
323335 thrust_source = thrust_source ,
324336 dry_inertia = dry_inertia ,
@@ -500,17 +512,25 @@ def geometry_dot(t, y):
500512
501513 # Compute state vector derivative
502514 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
515+ if self .only_radial_burn :
516+ burn_area = 2 * np .pi * (grain_inner_radius * grain_height )
517+
518+ grain_inner_radius_derivative = - volume_diff / burn_area
519+ grain_height_derivative = 0 # Set to zero to disable axial burning
520+
521+ else :
522+ burn_area = (
523+ 2
524+ * np .pi
525+ * (
526+ grain_outer_radius ** 2
527+ - grain_inner_radius ** 2
528+ + grain_inner_radius * grain_height
529+ )
510530 )
511- )
512- grain_inner_radius_derivative = - volume_diff / burn_area
513- grain_height_derivative = - 2 * grain_inner_radius_derivative
531+
532+ grain_inner_radius_derivative = - volume_diff / burn_area
533+ grain_height_derivative = - 2 * grain_inner_radius_derivative
514534
515535 return [grain_inner_radius_derivative , grain_height_derivative ]
516536
@@ -521,32 +541,55 @@ def geometry_jacobian(t, y):
521541
522542 # Compute jacobian
523543 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
544+ if self .only_radial_burn :
545+ factor = volume_diff / (
546+ 2 * np .pi * (grain_inner_radius * grain_height ) ** 2
531547 )
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
542548
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- ]
549+ inner_radius_derivative_wrt_inner_radius = factor * (
550+ grain_height - 2 * grain_inner_radius
551+ )
552+ inner_radius_derivative_wrt_height = 0
553+ height_derivative_wrt_inner_radius = 0
554+ height_derivative_wrt_height = 0
555+ # Height is a constant, so all the derivatives with respect to it are set to zero
556+
557+ return [
558+ [
559+ inner_radius_derivative_wrt_inner_radius ,
560+ inner_radius_derivative_wrt_height ,
561+ ],
562+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
563+ ]
564+
565+ else :
566+ factor = volume_diff / (
567+ 2
568+ * np .pi
569+ * (
570+ grain_outer_radius ** 2
571+ - grain_inner_radius ** 2
572+ + grain_inner_radius * grain_height
573+ )
574+ ** 2
575+ )
576+
577+ inner_radius_derivative_wrt_inner_radius = factor * (
578+ grain_height - 2 * grain_inner_radius
579+ )
580+ inner_radius_derivative_wrt_height = factor * grain_inner_radius
581+ height_derivative_wrt_inner_radius = (
582+ - 2 * inner_radius_derivative_wrt_inner_radius
583+ )
584+ height_derivative_wrt_height = - 2 * inner_radius_derivative_wrt_height
585+
586+ return [
587+ [
588+ inner_radius_derivative_wrt_inner_radius ,
589+ inner_radius_derivative_wrt_height ,
590+ ],
591+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
592+ ]
550593
551594 def terminate_burn (t , y ): # pylint: disable=unused-argument
552595 end_function = (self .grain_outer_radius - y [0 ]) * y [1 ]
@@ -597,16 +640,24 @@ def burn_area(self):
597640 burn_area : Function
598641 Function representing the burn area progression with the time.
599642 """
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
643+ if self .only_radial_burn :
644+ burn_area = (
645+ 2
646+ * np .pi
647+ * (self .grain_inner_radius * self .grain_height )
648+ * self .grain_number
649+ )
650+ else :
651+ burn_area = (
652+ 2
653+ * np .pi
654+ * (
655+ self .grain_outer_radius ** 2
656+ - self .grain_inner_radius ** 2
657+ + self .grain_inner_radius * self .grain_height
658+ )
659+ * self .grain_number
607660 )
608- * self .grain_number
609- )
610661 return burn_area
611662
612663 @funcify_method ("Time (s)" , "burn rate (m/s)" )
@@ -778,6 +829,7 @@ def to_dict(self, **kwargs):
778829 "grain_initial_height" : self .grain_initial_height ,
779830 "grain_separation" : self .grain_separation ,
780831 "grains_center_of_mass_position" : self .grains_center_of_mass_position ,
832+ "only_radial_burn" : self .only_radial_burn ,
781833 }
782834 )
783835
@@ -827,4 +879,5 @@ def from_dict(cls, data):
827879 interpolation_method = data ["interpolate" ],
828880 coordinate_system_orientation = data ["coordinate_system_orientation" ],
829881 reference_pressure = data .get ("reference_pressure" ),
882+ only_radial_burn = data .get ("only_radial_burn" , False ),
830883 )
0 commit comments