-
-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Expansion of Encoders Implementation for Full Flights. #679
base: develop
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #679 +/- ##
===========================================
+ Coverage 75.95% 76.46% +0.51%
===========================================
Files 99 95 -4
Lines 11237 11359 +122
===========================================
+ Hits 8535 8686 +151
+ Misses 2702 2673 -29 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing to complain about, good work.
} | ||
|
||
@classmethod | ||
def from_dict(cls, func_dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I`d like to see an example of you loading a class from the dict.
ENH: Simulation Save and Load in JSON Files
I have just noticed that I made a mistake when merging CHANGELOG conflicts for this PR. I will fix it before merging. This does not block reviewing.
|
"""Returns the class by importing its signature. | ||
|
||
Parameters | ||
---------- | ||
signature : str | ||
Signature of the class. | ||
|
||
Returns | ||
------- | ||
type | ||
Class defined by the signature. | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still cannot know what is a "class signature", is it the signature of the init class?
what do you have in the "signature" dictionary (which bte the docs says it is a str) exactly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I changed what is a signature
a few times during development. I will improve the docs.
@@ -60,3 +60,10 @@ def __str__(self): | |||
""" | |||
|
|||
return f"Fluid: {self.name}" | |||
|
|||
def to_dict(self, _): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually see this behavior in other packages, what do you think about it? I dont really understand the reasons of that tho.
def to_dict(self, _): | |
def to_dict(self, *): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, actually I think I will simply revert to having the parameter include_outputs
in all of them, and disable the warning if the method does not use it. That brings better standardization, since the call to_dict(include_outputs=...)
would always work.
The **
would be a better option than I used here, since it allows for the same interface as I mentioned. However, it also allows for other parameter names, and changing it in the future would be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall comments:
to_dict
andfrom_dict
methods are missing docstrings in all classes
def to_dict(self, include_outputs=True): | ||
data = { | ||
"rocket": self.rocket, | ||
"env": self.env, | ||
"rail_length": self.rail_length, | ||
"inclination": self.inclination, | ||
"heading": self.heading, | ||
"initial_solution": self.initial_solution, | ||
"terminate_on_apogee": self.terminate_on_apogee, | ||
"max_time": self.max_time, | ||
"max_time_step": self.max_time_step, | ||
"min_time_step": self.min_time_step, | ||
"rtol": self.rtol, | ||
"atol": self.atol, | ||
"time_overshoot": self.time_overshoot, | ||
"name": self.name, | ||
"equations_of_motion": self.equations_of_motion, | ||
} | ||
|
||
if include_outputs: | ||
data.update( | ||
{ | ||
"time": self.time, | ||
"out_of_rail_time": self.out_of_rail_time, | ||
"out_of_rail_velocity": self.out_of_rail_velocity, | ||
"out_of_rail_state": self.out_of_rail_state, | ||
"apogee": self.apogee, | ||
"apogee_time": self.apogee_time, | ||
"apogee_x": self.apogee_x, | ||
"apogee_y": self.apogee_y, | ||
"apogee_state": self.apogee_state, | ||
"x_impact": self.x_impact, | ||
"y_impact": self.y_impact, | ||
"impact_velocity": self.impact_velocity, | ||
"impact_state": self.impact_state, | ||
"x": self.x, | ||
"y": self.y, | ||
"z": self.z, | ||
"vx": self.vx, | ||
"vy": self.vy, | ||
"vz": self.vz, | ||
"e0": self.e0, | ||
"e1": self.e1, | ||
"e2": self.e2, | ||
"e3": self.e3, | ||
"w1": self.w1, | ||
"w2": self.w2, | ||
"w3": self.w3, | ||
"ax": self.ax, | ||
"ay": self.ay, | ||
"az": self.az, | ||
"alpha1": self.alpha1, | ||
"alpha2": self.alpha2, | ||
"alpha3": self.alpha3, | ||
"altitude": self.altitude, | ||
"mach_number": self.mach_number, | ||
"stream_velocity_x": self.stream_velocity_x, | ||
"stream_velocity_y": self.stream_velocity_y, | ||
"stream_velocity_z": self.stream_velocity_z, | ||
"free_stream_speed": self.free_stream_speed, | ||
"angle_of_attack": self.angle_of_attack, | ||
"static_margin": self.static_margin, | ||
"stability_margin": self.stability_margin, | ||
"latitude": self.latitude, | ||
"longitude": self.longitude, | ||
} | ||
) | ||
|
||
return data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these are just the __init__
arguments why not just use `inspect.signature(Flight.init).parameters to construct the data dict?
Also, I am pretty sure that all attributes/cached_properties can be accessed using dir()
or something similar...
I think some of the to_dict
and from_dict
can be generalized and might not need to be defined in every class. This reduces maintenance
@@ -373,6 +400,7 @@ def __init__(self, radius, height, spherical_caps=False, geometry_dict=None): | |||
""" | |||
geometry_dict = geometry_dict or {} | |||
super().__init__(geometry_dict) | |||
self.__input_radius = radius |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have support for tanks in Monte Carlo yet, but in Stochastic classes I believe that we require the input arguments of the __init__
method to be saved in the class as an attribute with the same name, e.g.:
def __init__(self, radius):
self.radius=radius
is there a way to avoid creating self.__input_radius
?
def __init__(self, *args, **kwargs): | ||
self.include_outputs = kwargs.pop("include_outputs", True) | ||
super().__init__(*args, **kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like making the default value of include_outputs
as False
will be much more useful. There will be more use cases for when it is false
I strongly advise to not include dosctrings yet. Also, they exists mainly for private reasons: we need them in order have the JSONEncoder working. Btw the methods are so simple that they don't even need docstrings. But that's a discussion for future sessions... |
Pull request type
Checklist
black rocketpy/ tests/
) has passed locallypytest tests -m slow --runslow
) have passed locallyCHANGELOG.md
has been updated (if relevant)Current behavior
Currently the
_encoding
module is just a stub and cannot still encode full simulations into a JSON like format.New behavior
This PR expand this module bringing the following:
to_dict
;Function
encoding.This PR also introduces decoding functionalities. The way this works is:
to_dict
orfrom_dict
method, they are used to perform the (de)encoding;Breaking change
Additional information
There is much to discuss here on the implementation and maintainability side of things. Main discussion points:
to_dict
and (in the future) afrom_dict
method to some (or all) rocketpy classes?_encoders
private.simplejson
: brings some more types and speed into encoding, but does not help much with custom types;jsonpickle
: really great for the typing handler (already writes by default each object type) and is able to serialize. The problem is that is does not handlefunctions/lambdas
and I did not find a good way to implement custom handlers for our use case;pickle / dill
: the most plug and play solution, however the output is not human readable and not generally compatible between different rocketpy versions.Of course, this is what I understood upon researching and testing, feel free to make any comments or suggest other modules.
Remarks and Future Considerations
Here are some of the steps that could be improved:
AirBrakes
+Controllers
and new classes.Some important remarks: