Skip to content
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: Callback function for collecting additional data from Monte Carlo sims #702

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

emtee14
Copy link

@emtee14 emtee14 commented Oct 6, 2024

Pull request type

  • Code changes (bugfix, features)

Checklist

  • Tests for the changes have been added (if needed)
  • Docs have been reviewed and added / updated
  • Lint (black rocketpy/ tests/) has passed locally
  • All tests (pytest tests -m slow --runslow) have passed locally
  • CHANGELOG.md has been updated (if relevant)

Current behaviour

Implementation for this feature suggestion #699 . At the moments users are limited to set variables when exporting data from Monte Carlo experiments.

New behaviour

Now a function can be passed to the MonteCarlo class which takes a Flight object as an argument and returns a dict to be appended to the default outputs.

Breaking change

  • No

Additional information

At the moment the implementation works but there is an existing issue with the RocketPyEncoder for writing the inputs to the .txt file as JSON strings. I've also made it check if the function overwrites existing variables though I feel this may not be necessary. I also had to fix how the previous results are imported as they are errors since text results can now be exported, see line 671.

@emtee14 emtee14 changed the base branch from master to develop October 6, 2024 21:18
@Gui-FernandesBR
Copy link
Member

Thanks for opening the PR @emtee14 , we will get back to you after the EuRoC competition, when our development team will be more available.

Copy link

codecov bot commented Oct 9, 2024

Codecov Report

Attention: Patch coverage is 36.36364% with 14 lines in your changes missing coverage. Please review.

Project coverage is 75.99%. Comparing base (a6a0f74) to head (afb4e3f).
Report is 13 commits behind head on develop.

Files with missing lines Patch % Lines
rocketpy/simulation/monte_carlo.py 33.33% 12 Missing ⚠️
rocketpy/prints/monte_carlo_prints.py 50.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #702      +/-   ##
===========================================
+ Coverage    75.95%   75.99%   +0.04%     
===========================================
  Files           99       95       -4     
  Lines        11237    11015     -222     
===========================================
- Hits          8535     8371     -164     
+ Misses        2702     2644      -58     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Lucas-Prates
Copy link
Contributor

@emtee14 thank you very much for opening this PR! I have been assigned to help you out with this feature. Your description in #699 and the (nice) implementation here give me a good idea of what you want to achieve.

To be more thorough, could you provide me an example of how you want to use it? Possibly a snippet of the code creating the export_function and calling the MonteCarlo class. It would be even better if it is an actual (maybe simplified?) example of what you are doing, e.g. exporting the environmental data mentioned in #699. If you want to give an example that is easy to run, consider the monte_carlo_class_usage.ipynb notebook and assume that this snippet would replace the code in the cell that calls the MonteCarlo class.

This would ensure that the design is best suited for the goal, and we could also add it as an example in the Monte Carlo usage notebook.

@emtee14
Copy link
Author

emtee14 commented Nov 11, 2024

Hi yes, I'll make an example that can be added to the docs. Another one of the uses we've found for it is exporting sensor data which we then use to run on our flight computer emulator allowing us to test firmware.

@Lucas-Prates Lucas-Prates marked this pull request as ready for review November 13, 2024 18:45
@Lucas-Prates Lucas-Prates requested a review from a team as a code owner November 13, 2024 18:45
@Lucas-Prates
Copy link
Contributor

Lucas-Prates commented Nov 13, 2024

This PR is ready for review. Along with the callback implementation provided by @emtee14, some error checks and tests were implemented. I provided a first simplified example on how to use this feature in the end of monte_carlo_class_usage.ipynb notebook, but am eager to see the example of @emtee14. Of course, his example can be provided in another PR as well, so there is no need to rush with the example.

Note: for some reason, codecov is not reflecting the test suite on the most recent commits. I am pretty sure I have covered most implemented lines.

Comment on lines +384 to +387
if key in self.export_list:
raise ValueError(
f"Invalid export function, returns dict which overwrites key, '{key}'"
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to do this once, I recommend moving this validation to somewhere in the init method so we don't need to re-run it every time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good idea to run this only once, but moving it to the init method might be problematic in the current implementation. The reasoning is as follows: to validate that there are no keys being overwritten, we have to call export_list so we can have the dictionary outputted by the callback. However, in order to make that call, we have to have the data from the simulations. I see two options:

  1. Create a "mock dictionary", or at least its keys, from export_function and make the test in the init method;
  2. Create a flag to check if export_function was validated. On the first call of these lines (inside __export_flight_data, we make the test and set the flag, hence halting further validations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good idea to run this only once, but moving it to the init method might be problematic in the current implementation. The reasoning is as follows: to validate that there are no keys being overwritten, we have to call export_list so we can have the dictionary outputted by the callback. However, in order to make that call, we have to have the data from the simulations. I see two options:

  1. Create a "mock dictionary", or at least its keys, from export_function and make the test in the init method;
  2. Create a flag to check if export_function was validated. On the first call of these lines (inside __export_flight_data, we make the test and set the flag, hence halting further validations.

@Lucas-Prates if we have a __check_export_list method, I think we should also have a __check_export_function as well. I like the idea of a mock_flight, but I don't know how hard it would be to make it happen.

I believe my other comment is related to this. If instead of a "callback function" that evaluates and returns a dictionary, maybe we should receive a dictionary with different callback functions. That way we could easily get the expected key names.

Other option is to not make any validation, let the user deal with the fact they will be overwriting the values if use the same name of variables in the dictionary.

export_function : callable, optional
A function which gets called at the end of a simulation to collect
additional data to be exported that isn't pre-defined. Takes the
Flight object as an argument and returns a dictionary. Default is None.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend specifying the dictionary structure. What are the keys and values? Can you give an example to anticipate users' curiosity?

Other thing is that once I read the name export_function I automatically imagine a callback function that returns a float, for example:

def mach_number(flight: Flight) -> float:
    return ...

export_function= mach_number

Therefore, unless this is only me that has such impression, I believe we could propose a better name for the argument. Maybe data_collectoror additional_data_collector.

Copy link
Member

@Gui-FernandesBR Gui-FernandesBR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you thought about the possibility of using both export_list and export_function at the same time?

@Lucas-Prates
Copy link
Contributor

Lucas-Prates commented Nov 15, 2024

have you thought about the possibility of using both export_list and export_function at the same time?

You mean using both in an example or replacing export_list functionality completely using export_function?

@Gui-FernandesBR
Copy link
Member

have you thought about the possibility of using both export_list and export_function at the same time?

You mean using both in an example or replacing export_list functionality completely using export_function?

have you thought about what would happen if someone uses both the export_list and export_function arguments at the same time (i.e. simultaneously)? Would that be a problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog
Development

Successfully merging this pull request may close these issues.

ENH: Callback function for collecting additional data from Monte Carlo sims
3 participants