@@ -544,15 +544,18 @@ def __init__(
544
heading : int, float, optional
544
heading : int, float, optional
545
Heading angle relative to north given in degrees.
545
Heading angle relative to north given in degrees.
546
Default is 90, which points in the x direction.
546
Default is 90, which points in the x direction.
547
- initialSolution : array, optional
547
+ initialSolution : array, Flight, optional
548
Initial solution array to be used. Format is
548
Initial solution array to be used. Format is
549
- initialSolution = [self.tInitial,
549
+ initialSolution = []
550
- xInit, yInit, zInit,
550
+ self.tInitial,
551
- vxInit, vyInit, vzInit,
551
+ xInit, yInit, zInit,
552
- e0Init, e1Init, e2Init, e3Init,
552
+ vxInit, vyInit, vzInit,
553
- w1Init, w2Init, w3Init].
553
+ e0Init, e1Init, e2Init, e3Init,
554
- If None, the initial solution will start with all null values,
554
+ w1Init, w2Init, w3Init
555
- except for the euler parameters which will be calculated based
555
+ ].
556
+ If a Flight object is used, the last state vector will be used as
557
+ initial solution. If None, the initial solution will start with
558
+ all null values, except for the euler parameters which will be calculated based
556
on given values of inclination and heading. Default is None.
559
on given values of inclination and heading. Default is None.
557
terminateOnApogee : boolean, optional
560
terminateOnApogee : boolean, optional
558
Whether to terminate simulation when rocket reaches apogee.
561
Whether to terminate simulation when rocket reaches apogee.
@@ -609,76 +612,11 @@ def __init__(
609
self .timeOvershoot = timeOvershoot
612
self .timeOvershoot = timeOvershoot
610
self .terminateOnApogee = terminateOnApogee
613
self .terminateOnApogee = terminateOnApogee
611
614
612
- # Modifying Rail Length for a better out of rail condition
613
- upperRButton = max (self .rocket .railButtons [0 ])
614
- lowerRButton = min (self .rocket .railButtons [0 ])
615
- nozzle = self .rocket .distanceRocketNozzle
616
- self .effective1RL = self .env .rL - abs (nozzle - upperRButton )
617
- self .effective2RL = self .env .rL - abs (nozzle - lowerRButton )
618
-
619
# Flight initialization
615
# Flight initialization
620
self .__init_post_process_variables ()
616
self .__init_post_process_variables ()
621
# Initialize solution monitors
617
# Initialize solution monitors
622
- self .outOfRailTime = 0
618
+ self .__init_solution_monitors ()
623
- self .outOfRailTimeIndex = 0
619
+ self .__init_flight_state ()
624
- self .outOfRailState = np .array ([0 ])
625
- self .outOfRailVelocity = 0
626
- self .apogeeState = np .array ([0 ])
627
- self .apogeeTime = 0
628
- self .apogeeX = 0
629
- self .apogeeY = 0
630
- self .apogee = 0
631
- self .xImpact = 0
632
- self .yImpact = 0
633
- self .impactVelocity = 0
634
- self .impactState = np .array ([0 ])
635
- self .parachuteEvents = []
636
- self .postProcessed = False
637
- # Initialize solver monitors
638
- self .functionEvaluations = []
639
- self .functionEvaluationsPerTimeStep = []
640
- self .timeSteps = []
641
- # Initialize solution state
642
- self .solution = []
643
- if self .initialSolution is None :
644
- # Initialize time and state variables
645
- self .tInitial = 0
646
- xInit , yInit , zInit = 0 , 0 , self .env .elevation
647
- vxInit , vyInit , vzInit = 0 , 0 , 0
648
- w1Init , w2Init , w3Init = 0 , 0 , 0
649
- # Initialize attitude
650
- psiInit = - heading * (np .pi / 180 ) # Precession / Heading Angle
651
- thetaInit = (inclination - 90 ) * (np .pi / 180 ) # Nutation Angle
652
- e0Init = np .cos (psiInit / 2 ) * np .cos (thetaInit / 2 )
653
- e1Init = np .cos (psiInit / 2 ) * np .sin (thetaInit / 2 )
654
- e2Init = np .sin (psiInit / 2 ) * np .sin (thetaInit / 2 )
655
- e3Init = np .sin (psiInit / 2 ) * np .cos (thetaInit / 2 )
656
- # Store initial conditions
657
- self .initialSolution = [
658
- self .tInitial ,
659
- xInit ,
660
- yInit ,
661
- zInit ,
662
- vxInit ,
663
- vyInit ,
664
- vzInit ,
665
- e0Init ,
666
- e1Init ,
667
- e2Init ,
668
- e3Init ,
669
- w1Init ,
670
- w2Init ,
671
- w3Init ,
672
- ]
673
- # Set initial derivative for rail phase
674
- self .initialDerivative = self .uDotRail1
675
- else :
676
- # Initial solution given, ignore rail phase
677
- # TODO: Check if rocket is actually out of rail. Otherwise, start at rail
678
- self .outOfRailState = self .initialSolution [1 :]
679
- self .outOfRailTime = self .initialSolution [0 ]
680
- self .outOfRailTimeIndex = 0
681
- self .initialDerivative = self .uDot
682
620
683
self .tInitial = self .initialSolution [0 ]
621
self .tInitial = self .initialSolution [0 ]
684
self .solution .append (self .initialSolution )
622
self .solution .append (self .initialSolution )
@@ -1118,6 +1056,81 @@ def __init__(
1118
if verbose :
1056
if verbose :
1119
print ("Simulation Completed at Time: {:3.4f} s" .format (self .t ))
1057
print ("Simulation Completed at Time: {:3.4f} s" .format (self .t ))
1120
1058
1059
+ def __init_flight_state (self ):
1060
+ """Initialize flight state variables."""
1061
+ if self .initialSolution is None :
1062
+ # Initialize time and state variables
1063
+ self .tInitial = 0
1064
+ xInit , yInit , zInit = 0 , 0 , self .env .elevation
1065
+ vxInit , vyInit , vzInit = 0 , 0 , 0
1066
+ w1Init , w2Init , w3Init = 0 , 0 , 0
1067
+ # Initialize attitude
1068
+ psiInit = - self .heading * (np .pi / 180 ) # Precession / Heading Angle
1069
+ thetaInit = (self .inclination - 90 ) * (np .pi / 180 ) # Nutation Angle
1070
+ e0Init = np .cos (psiInit / 2 ) * np .cos (thetaInit / 2 )
1071
+ e1Init = np .cos (psiInit / 2 ) * np .sin (thetaInit / 2 )
1072
+ e2Init = np .sin (psiInit / 2 ) * np .sin (thetaInit / 2 )
1073
+ e3Init = np .sin (psiInit / 2 ) * np .cos (thetaInit / 2 )
1074
+ # Store initial conditions
1075
+ self .initialSolution = [
1076
+ self .tInitial ,
1077
+ xInit ,
1078
+ yInit ,
1079
+ zInit ,
1080
+ vxInit ,
1081
+ vyInit ,
1082
+ vzInit ,
1083
+ e0Init ,
1084
+ e1Init ,
1085
+ e2Init ,
1086
+ e3Init ,
1087
+ w1Init ,
1088
+ w2Init ,
1089
+ w3Init ,
1090
+ ]
1091
+ # Set initial derivative for rail phase
1092
+ self .initialDerivative = self .uDotRail1
1093
+ elif isinstance (self .initialSolution , Flight ):
1094
+ # Initialize time and state variables based on last solution of
1095
+ # previous flight
1096
+ self .initialSolution = self .initialSolution .solution [- 1 ]
1097
+ # Set unused monitors
1098
+ self .outOfRailState = self .initialSolution [1 :]
1099
+ self .outOfRailTime = self .initialSolution [0 ]
1100
+ # Set initial derivative for 6-DOF flight phase
1101
+ self .initialDerivative = self .uDot
1102
+ else :
1103
+ # Initial solution given, ignore rail phase
1104
+ # TODO: Check if rocket is actually out of rail. Otherwise, start at rail
1105
+ self .outOfRailState = self .initialSolution [1 :]
1106
+ self .outOfRailTime = self .initialSolution [0 ]
1107
+ self .outOfRailTimeIndex = 0
1108
+ self .initialDerivative = self .uDot
1109
+
1110
+ def __init_solution_monitors (self ):
1111
+ """Initialize solution monitors."""
1112
+ self .outOfRailTime = 0
1113
+ self .outOfRailTimeIndex = 0
1114
+ self .outOfRailState = np .array ([0 ])
1115
+ self .outOfRailVelocity = 0
1116
+ self .apogeeState = np .array ([0 ])
1117
+ self .apogeeTime = 0
1118
+ self .apogeeX = 0
1119
+ self .apogeeY = 0
1120
+ self .apogee = 0
1121
+ self .xImpact = 0
1122
+ self .yImpact = 0
1123
+ self .impactVelocity = 0
1124
+ self .impactState = np .array ([0 ])
1125
+ self .parachuteEvents = []
1126
+ self .postProcessed = False
1127
+ # Initialize solver monitors
1128
+ self .functionEvaluations = []
1129
+ self .functionEvaluationsPerTimeStep = []
1130
+ self .timeSteps = []
1131
+ # Initialize solution state
1132
+ self .solution = []
1133
+
1121
def __init_post_process_variables (self ):
1134
def __init_post_process_variables (self ):
1122
"""Initialize post-process variables."""
1135
"""Initialize post-process variables."""
1123
# Initialize all variables calculated after initialization.
1136
# Initialize all variables calculated after initialization.
@@ -1126,6 +1139,29 @@ def __init_post_process_variables(self):
1126
self .difference = Function (0 )
1139
self .difference = Function (0 )
1127
self .safetyFactor = Function (0 )
1140
self .safetyFactor = Function (0 )
1128
1141
1142
+ @cached_property
1143
+ def effective1RL (self ):
1144
+ # Modifying Rail Length for a better out of rail condition
1145
+ nozzle = self .rocket .distanceRocketNozzle # Kinda works for single nozzle
1146
+ try :
1147
+ upperRButton = max (self .rocket .railButtons [0 ])
1148
+ except AttributeError : # If there is no rail button
1149
+ upperRButton = nozzle
1150
+ effective1RL = self .env .rL - abs (nozzle - upperRButton )
1151
+
1152
+ return effective1RL
1153
+
1154
+ @cached_property
1155
+ def effective2RL (self ):
1156
+ # Modifying Rail Length for a better out of rail condition
1157
+ nozzle = self .rocket .distanceRocketNozzle
1158
+ try :
1159
+ lowerRButton = min (self .rocket .railButtons [0 ])
1160
+ except AttributeError :
1161
+ lowerRButton = nozzle
1162
+ effective2RL = self .env .rL - abs (nozzle - lowerRButton )
1163
+ return effective2RL
1164
+
1129
def uDotRail1 (self , t , u , postProcessing = False ):
1165
def uDotRail1 (self , t , u , postProcessing = False ):
1130
"""Calculates derivative of u state vector with respect to time
1166
"""Calculates derivative of u state vector with respect to time
1131
when rocket is flying in 1 DOF motion in the rail.
1167
when rocket is flying in 1 DOF motion in the rail.
@@ -2309,7 +2345,9 @@ def retrieve_acceleration_arrays(self):
2309
callback (self )
2345
callback (self )
2310
# Loop through time steps in flight phase
2346
# Loop through time steps in flight phase
2311
for step in self .solution : # Can be optimized
2347
for step in self .solution : # Can be optimized
2312
- if initTime < step [0 ] <= finalTime :
2348
+ if initTime < step [0 ] <= finalTime or (
2349
+ initTime == self .tInitial and step [0 ] == self .tInitial
2350
+ ):
2313
# Get derivatives
2351
# Get derivatives
2314
uDot = currentDerivative (step [0 ], step [1 :])
2352
uDot = currentDerivative (step [0 ], step [1 :])
2315
# Get accelerations
2353
# Get accelerations
@@ -2397,7 +2435,9 @@ def retrieve_temporary_values_arrays(self):
2397
callback (self )
2435
callback (self )
2398
# Loop through time steps in flight phase
2436
# Loop through time steps in flight phase
2399
for step in self .solution : # Can be optimized
2437
for step in self .solution : # Can be optimized
2400
- if initTime < step [0 ] <= finalTime or (initTime == 0 and step [0 ] == 0 ):
2438
+ if initTime < step [0 ] <= finalTime or (
2439
+ initTime == self .tInitial and step [0 ] == self .tInitial
2440
+ ):
2401
# Call derivatives in post processing mode
2441
# Call derivatives in post processing mode
2402
uDot = currentDerivative (step [0 ], step [1 :], postProcessing = True )
2442
uDot = currentDerivative (step [0 ], step [1 :], postProcessing = True )
2403
2443
@@ -3171,7 +3211,8 @@ def plotTrajectoryForceData(self):
3171
eventTimeIndex = - 1
3211
eventTimeIndex = - 1
3172
3212
3173
# Rail Button Forces
3213
# Rail Button Forces
3174
- fig6 = plt .figure (figsize = (9 , 6 ))
3214
+ if self .rocket .railButtons is not None :
3215
+ fig6 = plt .figure (figsize = (9 , 6 ))
3175
3216
3176
ax1 = plt .subplot (211 )
3217
ax1 = plt .subplot (211 )
3177
ax1 .plot (
3218
ax1 .plot (
0 commit comments