@@ -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
@@ -405,6 +418,10 @@ def exhaust_velocity(self):
405418 self .total_impulse / self .propellant_initial_mass
406419 ).set_discrete_based_on_model (self .thrust )
407420
421+ # @property
422+ # def only_radial_burn(self):
423+ # return self._only_radial_burn
424+
408425 @property
409426 def propellant_initial_mass (self ):
410427 """Returns the initial propellant mass.
@@ -500,17 +517,25 @@ def geometry_dot(t, y):
500517
501518 # Compute state vector derivative
502519 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
520+ if self .only_radial_burn :
521+ burn_area = 2 * np .pi * (grain_inner_radius * grain_height )
522+
523+ grain_inner_radius_derivative = - volume_diff / burn_area
524+ grain_height_derivative = 0 # Set to zero to disable axial burning
525+
526+ else :
527+ burn_area = (
528+ 2
529+ * np .pi
530+ * (
531+ grain_outer_radius ** 2
532+ - grain_inner_radius ** 2
533+ + grain_inner_radius * grain_height
534+ )
510535 )
511- )
512- grain_inner_radius_derivative = - volume_diff / burn_area
513- grain_height_derivative = - 2 * grain_inner_radius_derivative
536+
537+ grain_inner_radius_derivative = - volume_diff / burn_area
538+ grain_height_derivative = - 2 * grain_inner_radius_derivative
514539
515540 return [grain_inner_radius_derivative , grain_height_derivative ]
516541
@@ -521,32 +546,55 @@ def geometry_jacobian(t, y):
521546
522547 # Compute jacobian
523548 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
549+ if self .only_radial_burn :
550+ factor = volume_diff / (
551+ 2 * np .pi * (grain_inner_radius * grain_height ) ** 2
531552 )
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
542553
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- ]
554+ inner_radius_derivative_wrt_inner_radius = factor * (
555+ grain_height - 2 * grain_inner_radius
556+ )
557+ inner_radius_derivative_wrt_height = 0
558+ height_derivative_wrt_inner_radius = 0
559+ height_derivative_wrt_height = 0
560+ # Height is a constant, so all the derivatives with respect to it are set to zero
561+
562+ return [
563+ [
564+ inner_radius_derivative_wrt_inner_radius ,
565+ inner_radius_derivative_wrt_height ,
566+ ],
567+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
568+ ]
569+
570+ else :
571+ factor = volume_diff / (
572+ 2
573+ * np .pi
574+ * (
575+ grain_outer_radius ** 2
576+ - grain_inner_radius ** 2
577+ + grain_inner_radius * grain_height
578+ )
579+ ** 2
580+ )
581+
582+ inner_radius_derivative_wrt_inner_radius = factor * (
583+ grain_height - 2 * grain_inner_radius
584+ )
585+ inner_radius_derivative_wrt_height = factor * grain_inner_radius
586+ height_derivative_wrt_inner_radius = (
587+ - 2 * inner_radius_derivative_wrt_inner_radius
588+ )
589+ height_derivative_wrt_height = - 2 * inner_radius_derivative_wrt_height
590+
591+ return [
592+ [
593+ inner_radius_derivative_wrt_inner_radius ,
594+ inner_radius_derivative_wrt_height ,
595+ ],
596+ [height_derivative_wrt_inner_radius , height_derivative_wrt_height ],
597+ ]
550598
551599 def terminate_burn (t , y ): # pylint: disable=unused-argument
552600 end_function = (self .grain_outer_radius - y [0 ]) * y [1 ]
@@ -597,16 +645,24 @@ def burn_area(self):
597645 burn_area : Function
598646 Function representing the burn area progression with the time.
599647 """
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
648+ if self .only_radial_burn :
649+ burn_area = (
650+ 2
651+ * np .pi
652+ * (self .grain_inner_radius * self .grain_height )
653+ * self .grain_number
654+ )
655+ else :
656+ burn_area = (
657+ 2
658+ * np .pi
659+ * (
660+ self .grain_outer_radius ** 2
661+ - self .grain_inner_radius ** 2
662+ + self .grain_inner_radius * self .grain_height
663+ )
664+ * self .grain_number
607665 )
608- * self .grain_number
609- )
610666 return burn_area
611667
612668 @funcify_method ("Time (s)" , "burn rate (m/s)" )
@@ -778,6 +834,7 @@ def to_dict(self, **kwargs):
778834 "grain_initial_height" : self .grain_initial_height ,
779835 "grain_separation" : self .grain_separation ,
780836 "grains_center_of_mass_position" : self .grains_center_of_mass_position ,
837+ "only_radial_burn" : self .only_radial_burn ,
781838 }
782839 )
783840
@@ -827,4 +884,5 @@ def from_dict(cls, data):
827884 interpolation_method = data ["interpolate" ],
828885 coordinate_system_orientation = data ["coordinate_system_orientation" ],
829886 reference_pressure = data .get ("reference_pressure" ),
887+ only_radial_burn = data .get ("only_radial_burn" , False ),
830888 )
0 commit comments