Skip to content

Commit 99591c7

Browse files
committed
ENH: add an option to discretize callable sources encoding.
1 parent 5b625a8 commit 99591c7

22 files changed

Lines changed: 284 additions & 140 deletions

rocketpy/_encoders.py

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,13 @@ class RocketPyEncoder(json.JSONEncoder):
1717

1818
def __init__(self, *args, **kwargs):
1919
self.include_outputs = kwargs.pop("include_outputs", False)
20+
self.discretize = kwargs.pop("discretize", False)
2021
self.include_function_data = kwargs.pop("include_function_data", True)
2122
super().__init__(*args, **kwargs)
2223

2324
def default(self, o):
24-
if isinstance(
25-
o,
26-
(
27-
np.int_,
28-
np.intc,
29-
np.intp,
30-
np.int8,
31-
np.int16,
32-
np.int32,
33-
np.int64,
34-
np.uint8,
35-
np.uint16,
36-
np.uint32,
37-
np.uint64,
38-
),
39-
):
40-
return int(o)
41-
elif isinstance(o, (np.float16, np.float32, np.float64)):
42-
return float(o)
25+
if isinstance(o, np.generic):
26+
return o.item()
4327
elif isinstance(o, np.ndarray):
4428
return o.tolist()
4529
elif isinstance(o, datetime):
@@ -50,11 +34,15 @@ def default(self, o):
5034
if not self.include_function_data:
5135
return str(o)
5236
else:
53-
encoding = o.to_dict(self.include_outputs)
37+
encoding = o.to_dict(
38+
include_outputs=self.include_outputs, discretize=self.discretize
39+
)
5440
encoding["signature"] = get_class_signature(o)
5541
return encoding
5642
elif hasattr(o, "to_dict"):
57-
encoding = o.to_dict(self.include_outputs)
43+
encoding = o.to_dict(
44+
include_outputs=self.include_outputs, discretize=self.discretize
45+
)
5846
encoding = remove_circular_references(encoding)
5947

6048
encoding["signature"] = get_class_signature(o)

rocketpy/environment/environment.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,7 +2702,21 @@ def decimal_degrees_to_arc_seconds(angle):
27022702
arc_seconds = (remainder * 60 - arc_minutes) * 60
27032703
return degrees, arc_minutes, arc_seconds
27042704

2705-
def to_dict(self, include_outputs=False):
2705+
def to_dict(self, **kwargs):
2706+
wind_velocity_x = self.wind_velocity_x
2707+
wind_velocity_y = self.wind_velocity_y
2708+
wind_heading = self.wind_heading
2709+
wind_direction = self.wind_direction
2710+
wind_speed = self.wind_speed
2711+
density = self.density
2712+
if kwargs.get("discretize", False):
2713+
wind_velocity_x = wind_velocity_x.set_discrete(0, self.max_expected_height)
2714+
wind_velocity_y = wind_velocity_y.set_discrete(0, self.max_expected_height)
2715+
wind_heading = wind_heading.set_discrete(0, self.max_expected_height)
2716+
wind_direction = wind_direction.set_discrete(0, self.max_expected_height)
2717+
wind_speed = wind_speed.set_discrete(0, self.max_expected_height)
2718+
density = density.set_discrete(0, self.max_expected_height)
2719+
27062720
env_dict = {
27072721
"gravity": self.gravity,
27082722
"date": self.date,
@@ -2715,15 +2729,15 @@ def to_dict(self, include_outputs=False):
27152729
"atmospheric_model_type": self.atmospheric_model_type,
27162730
"pressure": self.pressure,
27172731
"temperature": self.temperature,
2718-
"wind_velocity_x": self.wind_velocity_x,
2719-
"wind_velocity_y": self.wind_velocity_y,
2720-
"wind_heading": self.wind_heading,
2721-
"wind_direction": self.wind_direction,
2722-
"wind_speed": self.wind_speed,
2732+
"wind_velocity_x": wind_velocity_x,
2733+
"wind_velocity_y": wind_velocity_y,
2734+
"wind_heading": wind_heading,
2735+
"wind_direction": wind_direction,
2736+
"wind_speed": wind_speed,
27232737
}
27242738

2725-
if include_outputs:
2726-
env_dict["density"] = self.density
2739+
if kwargs.get("include_outputs", False):
2740+
env_dict["density"] = density
27272741
env_dict["barometric_height"] = self.barometric_height
27282742
env_dict["speed_of_sound"] = self.speed_of_sound
27292743
env_dict["dynamic_viscosity"] = self.dynamic_viscosity

rocketpy/mathutils/function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3567,7 +3567,7 @@ def __validate_extrapolation(self, extrapolation):
35673567
extrapolation = "natural"
35683568
return extrapolation
35693569

3570-
def to_dict(self, include_outputs=False): # pylint: disable=unused-argument
3570+
def to_dict(self, **kwargs): # pylint: disable=unused-argument
35713571
"""Serializes the Function instance to a dictionary.
35723572
35733573
Returns

rocketpy/mathutils/vector_matrix.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ def zeros():
403403
"""Returns the zero vector."""
404404
return Vector([0, 0, 0])
405405

406-
def to_dict(self, include_outputs=False): # pylint: disable=unused-argument
406+
def to_dict(self, **kwargs): # pylint: disable=unused-argument
407407
"""Returns the vector as a JSON compatible element."""
408408
return list(self.components)
409409

@@ -1007,7 +1007,7 @@ def __repr__(self):
10071007
+ f" [{self.zx}, {self.zy}, {self.zz}])"
10081008
)
10091009

1010-
def to_dict(self, include_outputs=False): # pylint: disable=unused-argument
1010+
def to_dict(self, **kwargs): # pylint: disable=unused-argument
10111011
"""Returns the matrix as a JSON compatible element."""
10121012
return [list(row) for row in self.components]
10131013

rocketpy/motors/fluid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __str__(self):
6161

6262
return f"Fluid: {self.name}"
6363

64-
def to_dict(self, include_outputs=False): # pylint: disable=unused-argument
64+
def to_dict(self, **kwargs): # pylint: disable=unused-argument
6565
return {"name": self.name, "density": self.density}
6666

6767
@classmethod

rocketpy/motors/hybrid_motor.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ def draw(self, *, filename=None):
641641
"""
642642
self.plots.draw(filename=filename)
643643

644-
def to_dict(self, include_outputs=False):
645-
data = super().to_dict(include_outputs)
644+
def to_dict(self, **kwargs):
645+
data = super().to_dict(**kwargs)
646646
data.update(
647647
{
648648
"grain_number": self.grain_number,
@@ -660,13 +660,18 @@ def to_dict(self, include_outputs=False):
660660
}
661661
)
662662

663-
if include_outputs:
663+
if kwargs.get("include_outputs", False):
664+
burn_rate = self.solid.burn_rate
665+
if kwargs.get("discretize", False):
666+
burn_rate = burn_rate.set_discrete_based_on_model(
667+
self.thrust, mutate_self=False
668+
)
664669
data.update(
665670
{
666671
"grain_inner_radius": self.solid.grain_inner_radius,
667672
"grain_height": self.solid.grain_height,
668673
"burn_area": self.solid.burn_area,
669-
"burn_rate": self.solid.burn_rate,
674+
"burn_rate": burn_rate,
670675
}
671676
)
672677

rocketpy/motors/liquid_motor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,8 @@ def draw(self, *, filename=None):
497497
"""
498498
self.plots.draw(filename=filename)
499499

500-
def to_dict(self, include_outputs=False):
501-
data = super().to_dict(include_outputs)
500+
def to_dict(self, **kwargs):
501+
data = super().to_dict(**kwargs)
502502
data.update(
503503
{
504504
"positioned_tanks": [

rocketpy/motors/motor.py

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,14 +1231,7 @@ def get_attr_value(obj, attr_name, multiplier=1):
12311231
# Write last line
12321232
file.write(f"{self.thrust.source[-1, 0]:.4f} {0:.3f}\n")
12331233

1234-
def to_dict(self, include_outputs=False):
1235-
thrust_source = self.thrust_source
1236-
1237-
if isinstance(thrust_source, str):
1238-
thrust_source = self.thrust.source
1239-
elif callable(thrust_source) and not isinstance(thrust_source, Function):
1240-
thrust_source = Function(thrust_source)
1241-
1234+
def to_dict(self, **kwargs):
12421235
data = {
12431236
"thrust_source": self.thrust,
12441237
"dry_I_11": self.dry_I_11,
@@ -1258,31 +1251,94 @@ def to_dict(self, include_outputs=False):
12581251
"reference_pressure": self.reference_pressure,
12591252
}
12601253

1261-
if include_outputs:
1254+
if kwargs.get("include_outputs", False):
1255+
total_mass = self.total_mass
1256+
propellant_mass = self.propellant_mass
1257+
mass_flow_rate = self.total_mass_flow_rate
1258+
center_of_mass = self.center_of_mass
1259+
center_of_propellant_mass = self.center_of_propellant_mass
1260+
exhaust_velocity = self.exhaust_velocity
1261+
I_11 = self.I_11
1262+
I_22 = self.I_22
1263+
I_33 = self.I_33
1264+
I_12 = self.I_12
1265+
I_13 = self.I_13
1266+
I_23 = self.I_23
1267+
propellant_I_11 = self.propellant_I_11
1268+
propellant_I_22 = self.propellant_I_22
1269+
propellant_I_33 = self.propellant_I_33
1270+
propellant_I_12 = self.propellant_I_12
1271+
propellant_I_13 = self.propellant_I_13
1272+
propellant_I_23 = self.propellant_I_23
1273+
if kwargs.get("discretize", False):
1274+
total_mass = total_mass.set_discrete_based_on_model(
1275+
self.thrust, mutate_self=False
1276+
)
1277+
propellant_mass = propellant_mass.set_discrete_based_on_model(
1278+
self.thrust, mutate_self=False
1279+
)
1280+
mass_flow_rate = mass_flow_rate.set_discrete_based_on_model(
1281+
self.thrust, mutate_self=False
1282+
)
1283+
center_of_mass = center_of_mass.set_discrete_based_on_model(
1284+
self.thrust, mutate_self=False
1285+
)
1286+
center_of_propellant_mass = (
1287+
center_of_propellant_mass.set_discrete_based_on_model(
1288+
self.thrust, mutate_self=False
1289+
)
1290+
)
1291+
exhaust_velocity = exhaust_velocity.set_discrete_based_on_model(
1292+
self.thrust, mutate_self=False
1293+
)
1294+
I_11 = I_11.set_discrete_based_on_model(self.thrust, mutate_self=False)
1295+
I_22 = I_22.set_discrete_based_on_model(self.thrust, mutate_self=False)
1296+
I_33 = I_33.set_discrete_based_on_model(self.thrust, mutate_self=False)
1297+
I_12 = I_12.set_discrete_based_on_model(self.thrust, mutate_self=False)
1298+
I_13 = I_13.set_discrete_based_on_model(self.thrust, mutate_self=False)
1299+
I_23 = I_23.set_discrete_based_on_model(self.thrust, mutate_self=False)
1300+
propellant_I_11 = propellant_I_11.set_discrete_based_on_model(
1301+
self.thrust, mutate_self=False
1302+
)
1303+
propellant_I_22 = propellant_I_22.set_discrete_based_on_model(
1304+
self.thrust, mutate_self=False
1305+
)
1306+
propellant_I_33 = propellant_I_33.set_discrete_based_on_model(
1307+
self.thrust, mutate_self=False
1308+
)
1309+
propellant_I_12 = propellant_I_12.set_discrete_based_on_model(
1310+
self.thrust, mutate_self=False
1311+
)
1312+
propellant_I_13 = propellant_I_13.set_discrete_based_on_model(
1313+
self.thrust, mutate_self=False
1314+
)
1315+
propellant_I_23 = propellant_I_23.set_discrete_based_on_model(
1316+
self.thrust, mutate_self=False
1317+
)
12621318
data.update(
12631319
{
12641320
"vacuum_thrust": self.vacuum_thrust,
1265-
"total_mass": self.total_mass,
1266-
"propellant_mass": self.propellant_mass,
1267-
"mass_flow_rate": self.mass_flow_rate,
1268-
"center_of_mass": self.center_of_mass,
1269-
"center_of_propellant_mass": self.center_of_propellant_mass,
1321+
"total_mass": total_mass,
1322+
"propellant_mass": propellant_mass,
1323+
"mass_flow_rate": mass_flow_rate,
1324+
"center_of_mass": center_of_mass,
1325+
"center_of_propellant_mass": center_of_propellant_mass,
12701326
"total_impulse": self.total_impulse,
1271-
"exhaust_velocity": self.exhaust_velocity,
1327+
"exhaust_velocity": exhaust_velocity,
12721328
"propellant_initial_mass": self.propellant_initial_mass,
12731329
"structural_mass_ratio": self.structural_mass_ratio,
1274-
"I_11": self.I_11,
1275-
"I_22": self.I_22,
1276-
"I_33": self.I_33,
1277-
"I_12": self.I_12,
1278-
"I_13": self.I_13,
1279-
"I_23": self.I_23,
1280-
"propellant_I_11": self.propellant_I_11,
1281-
"propellant_I_22": self.propellant_I_22,
1282-
"propellant_I_33": self.propellant_I_33,
1283-
"propellant_I_12": self.propellant_I_12,
1284-
"propellant_I_13": self.propellant_I_13,
1285-
"propellant_I_23": self.propellant_I_23,
1330+
"I_11": I_11,
1331+
"I_22": I_22,
1332+
"I_33": I_33,
1333+
"I_12": I_12,
1334+
"I_13": I_13,
1335+
"I_23": I_23,
1336+
"propellant_I_11": propellant_I_11,
1337+
"propellant_I_22": propellant_I_22,
1338+
"propellant_I_33": propellant_I_33,
1339+
"propellant_I_12": propellant_I_12,
1340+
"propellant_I_13": propellant_I_13,
1341+
"propellant_I_23": propellant_I_23,
12861342
}
12871343
)
12881344

@@ -1510,7 +1566,7 @@ def center_of_propellant_mass(self):
15101566
Function
15111567
Function representing the center of mass of the motor.
15121568
"""
1513-
return self.chamber_position
1569+
return Function(self.chamber_position).set_discrete_based_on_model(self.thrust)
15141570

15151571
@funcify_method("Time (s)", "Inertia I_11 (kg m²)")
15161572
def propellant_I_11(self):
@@ -1532,11 +1588,11 @@ def propellant_I_11(self):
15321588
----------
15331589
https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor
15341590
"""
1535-
return (
1591+
return Function(
15361592
self.propellant_mass
15371593
* (3 * self.chamber_radius**2 + self.chamber_height**2)
15381594
/ 12
1539-
)
1595+
).set_discrete_based_on_model(self.thrust)
15401596

15411597
@funcify_method("Time (s)", "Inertia I_22 (kg m²)")
15421598
def propellant_I_22(self):
@@ -1580,19 +1636,21 @@ def propellant_I_33(self):
15801636
----------
15811637
https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor
15821638
"""
1583-
return self.propellant_mass * self.chamber_radius**2 / 2
1639+
return Function(
1640+
self.propellant_mass * self.chamber_radius**2 / 2
1641+
).set_discrete_based_on_model(self.thrust)
15841642

15851643
@funcify_method("Time (s)", "Inertia I_12 (kg m²)")
15861644
def propellant_I_12(self):
1587-
return Function(0)
1645+
return Function(0).set_discrete_based_on_model(self.thrust)
15881646

15891647
@funcify_method("Time (s)", "Inertia I_13 (kg m²)")
15901648
def propellant_I_13(self):
1591-
return Function(0)
1649+
return Function(0).set_discrete_based_on_model(self.thrust)
15921650

15931651
@funcify_method("Time (s)", "Inertia I_23 (kg m²)")
15941652
def propellant_I_23(self):
1595-
return Function(0)
1653+
return Function(0).set_discrete_based_on_model(self.thrust)
15961654

15971655
@staticmethod
15981656
def load_from_eng_file(
@@ -1862,8 +1920,8 @@ def all_info(self):
18621920
self.prints.all()
18631921
self.plots.all()
18641922

1865-
def to_dict(self, include_outputs=False):
1866-
data = super().to_dict(include_outputs)
1923+
def to_dict(self, **kwargs):
1924+
data = super().to_dict(**kwargs)
18671925
data.update(
18681926
{
18691927
"chamber_radius": self.chamber_radius,

rocketpy/motors/solid_motor.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,8 @@ def draw(self, *, filename=None):
765765
"""
766766
self.plots.draw(filename=filename)
767767

768-
def to_dict(self, include_outputs=False):
769-
data = super().to_dict(include_outputs)
768+
def to_dict(self, **kwargs):
769+
data = super().to_dict(**kwargs)
770770
data.update(
771771
{
772772
"nozzle_radius": self.nozzle_radius,
@@ -781,13 +781,18 @@ def to_dict(self, include_outputs=False):
781781
}
782782
)
783783

784-
if include_outputs:
784+
if kwargs.get("include_outputs", False):
785+
burn_rate = self.burn_rate
786+
if kwargs.get("discretize", False):
787+
burn_rate = burn_rate.set_discrete_based_on_model(
788+
self.thrust, mutate_self=False
789+
)
785790
data.update(
786791
{
787792
"grain_inner_radius": self.grain_inner_radius,
788793
"grain_height": self.grain_height,
789794
"burn_area": self.burn_area,
790-
"burn_rate": self.burn_rate,
795+
"burn_rate": burn_rate,
791796
"Kn": self.Kn,
792797
}
793798
)

0 commit comments

Comments
 (0)