Skip to content

ENH: Compare trajectories method #227

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

Merged
merged 7 commits into from
Sep 13, 2022

Conversation

Gui-FernandesBR
Copy link
Member

@Gui-FernandesBR Gui-FernandesBR commented Sep 12, 2022

Pull request type

  • Code base additions (bugfix, features)

Pull request checklist

  • Code base additions (for bug fixes / features):

    • Tests for the changes have been added
    • Docs have been reviewed and added / updated if needed
    • Lint (black rocketpy) has passed locally and any fixes were made
    • All tests (pytest --runslow) have passed locally

What is the current behavior?

There's no pre-build method to allow us easily create plots for combined trajectories, e.g. multi-stage rockets.

What is the new behavior?

I've used some code examples to implement an auxiliary function at utilities, which will allow us to create useful plots for some applications.
A simple function to plot the diffferent flight trajectories at the same matplotlib figure.

Expected behavior:

Code example:

trajectory1 = (RocketFlight1.x[:,1], RocketFlight1.y[:,1], RocketFlight1.z[:,1]-RocketFlight1.env.elevation)
trajectory2 = (RocketFlight2.x[:,1], RocketFlight2.y[:,1], RocketFlight2.z[:,1]-RocketFlight2.env.elevation)
trajectory3 = (PayloadFlight.x[:,1], PayloadFlight.y[:,1], PayloadFlight.z[:,1]-PayloadFlight.env.elevation)
combineTrajectories(trajectory1, trajectory2, trajectory3)

Result:

image

Does this introduce a breaking change?

  • Yes
  • No

Other information

This is a part of "complex_simulations", which will give use some work with new simulations examples, such as deployable payloads flights and others.

@Gui-FernandesBR
Copy link
Member Author

@MateusStano @FranzYuri , could one of your review/approve/merge this one?

@MateusStano
Copy link
Member

Hey, nice one! Just wondering is there a reason for the function to receive the trajectories instead of receiving the Flight objects right away?

@MateusStano
Copy link
Member

I altered the code so that it receives Flight objects instead. I also solved some TODOs while at it.

Here is a preview


def compareTrajectories(
    list_of_flights,
    name=None,
    legend=True,
):
    """Returns a trajectory that is the combination of the trajectories passed
    All components of the trajectory (x, y, z) must be at the same length.
    Minimum of 1 trajectory is required.
    Current a maximum of 5 trajectories can be combined.
    The trajectories must be in the same reference frame.
    The z coordinate must be referenced to the ground or to the sea level, but
    it is important that all trajectories are passed in the same reference.
    This function was created based two source-codes:
    - Mateus Stano: https://github.com/RocketPy-Team/Hackathon_2020/pull/123/files#diff-8f0a881d1355d1748074d56ed43129d46db5b755acaa753e3c49143a1c800386
    - Dyllon Preston: https://github.com/Dyllon-P/MBS-Template/blob/main/MBS.py

    """
    # TODO: Allow the user to catch different planes (xy, yz, xz) from the main plot
    # TODO: Allow the user to set the colors
    # TODO: Make the legend optional
    # TODO: Allow the user to set the line style
    # TODO: Improve docs

    # Initialize variables
    maxZ = 0
    maxX = 0
    minX = 0
    minY = 0
    maxY = 0
    maxXY = 0
    minXY = 0
    counter = 0
    name = (
        [("Trajectory " + str(i + 1)) for i in range(len(list_of_flights))]
        if name == None
        else name
    )

    # Initialize Figure
    fig1 = plt.figure(figsize=(9, 9))
    ax1 = plt.subplot(111, projection="3d")

    # Iterate through Flight objects
    for flight in list_of_flights:

        # Check post process
        if flight.postProcessed is False:
            flight.postProcess()

        # Get trajectories
        x = flight.x[:, 1]
        y = flight.y[:, 1]
        z = flight.z[:, 1] - flight.env.elevation

        # Find max/min values for each component
        maxZ = max(z) if max(z) > maxZ else maxZ
        maxX = max(x) if max(x) > maxX else maxX
        minX = min(x) if min(x) > minX else minX
        minY = min(x) if min(x) > minX else minX
        maxY = max(y) if max(y) > maxY else maxY
        maxXY = max(maxX, maxY) if max(maxX, maxY) > maxXY else maxXY
        minXY = min(minX, minY) if min(minX, minY) > minXY else minXY

        # Plot Trajectory
        ax1.plot(x, y, z, linewidth="2", label=name[counter])
        counter += 1

    ax1.scatter(0, 0, 0)
    ax1.set_xlabel("X - East (m)")
    ax1.set_ylabel("Y - North (m)")
    ax1.set_zlabel("Z - Altitude (m)")
    ax1.set_title("Flight Trajectory")
    ax1.set_zlim3d([0, maxZ])
    ax1.set_ylim3d([minXY, maxXY])
    ax1.set_xlim3d([minXY, maxXY])
    ax1.view_init(15, 45)
    plt.legend(legend)
    plt.show()

    return None

Tell me what you think, I can commit it right away

@giovaniceotto
Copy link
Member

Don't forget to make the method documentation compliant to our docs style (Numpy-style docstrings).

@giovaniceotto
Copy link
Member

@MateusStano implementation seems like a welcome improvement!

@Gui-FernandesBR
Copy link
Member Author

@MateusStano implementation seems like a welcome improvement!

Definitely! This commit will help us a lot

@giovaniceotto
Copy link
Member

I would add that support for non Flight objects may also be very interesting for use cases such as comparing openRocket flights to RocketPy, or comparing real flight data.

@Gui-FernandesBR
Copy link
Member Author

I guess those are different paradigms... One is to combine different flight phases of a non-conventional flights, for instance, deployable payloads and milti-stage rockets. The other is to plot two (or more) series and compare one against each other.

Perhaps they can be treated by the same methods when plotting 3D trajectory, but the idea is a bit different.

@giovaniceotto
Copy link
Member

I see. I think we are getting a little bit confused here. @MateusStano's function is called compareTrajectories.

I guess we need a class method in the Flight class called mergeFlights and a function in the utilites file called compareFlights.

@Gui-FernandesBR
Copy link
Member Author

I would recommend proceeding by separating Stano's function into 2 other functions, one takes lists as input, and orher takes flights.

We can setup a manner that the second opens the flight object, take the lists and call the first function.

@Gui-FernandesBR
Copy link
Member Author

I see. I think we are getting a little bit confused here. @MateusStano's function is called compareTrajectories.

I guess we need a class method in the Flight class called mergeFlights and a function in the utilites file called compareFlights.

Please describe this mergeFlights idea, I'm still not getting it

@MateusStano
Copy link
Member

I guess we need a class method in the Flight class called mergeFlights and a function in the utilites file called compareFlights.

I don't know if I understood the mergeFlights method, or why it would be in the Flight class. To me it makes more sense for it to be in utilities for now

But I think having two different functions here is useful. One for comparing Flight objects and one for comparing trajectories in general. I commited the two functions @Gui-FernandesBR check if they are doing what you needed

@Gui-FernandesBR
Copy link
Member Author

Everything looks great now. @MateusStano thank you so much for your addition, I've made some quick adjustments and believe we can proceed. Would you re-review/approve/merge please?

@giovaniceotto , I'm still open if you want to discuss the mergeFlights idea that you mentioned, but I think the current contribution already achieved its porpouse.

Indeed, I've already done a quick deployable payload simulation, and there's something that is really bothering me which is the idea of `finishing a "first-stage" flight -> save the final state vector -> Start a new Flight object again". I'm thinking of somehow utilize a "modifyRocket" inside the Flight Class. This way you still keep in the same flight, but with a different rocket.
That's something to discuss in our next meeting!

@giovaniceotto
Copy link
Member

This PR is named COMBINE flights, but it is implementing a COMPARE flights. Is this correct?

The mergeFlights idea would be to have two or more flights combined/merged into a single flight object.

@MateusStano MateusStano merged commit f68aea8 into enh/complex_simulations Sep 13, 2022
@Gui-FernandesBR Gui-FernandesBR changed the title ENH: Combine trajectories method ENH: Compare trajectories method Sep 14, 2022
@Gui-FernandesBR Gui-FernandesBR deleted the enh/combine_trajectories branch September 20, 2022 01:03
@Gui-FernandesBR Gui-FernandesBR added the Outputs Dedicated to visualizations enhancements like prints and plots label Sep 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Outputs Dedicated to visualizations enhancements like prints and plots
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants