Skip to content

Commit

Permalink
Merge pull request #480 from fast-aircraft-design/payload-range-with-…
Browse files Browse the repository at this point in the history
…plot

Payload-range plot
  • Loading branch information
christophe-david committed Mar 14, 2023
2 parents 6e6257e + 9266f2c commit 2b40991
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/fastoad/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
mass_breakdown_bar_plot,
mass_breakdown_sun_plot,
wing_geometry_plot,
payload_range_plot,
)
from .mission_viewer import MissionViewer
from .optimization_viewer import OptimizationViewer
Expand Down
114 changes: 114 additions & 0 deletions src/fastoad/gui/analysis_and_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,120 @@ def mass_breakdown_sun_plot(
return fig


def payload_range_plot(
aircraft_file_path: str,
name="Payload-Range",
mission_name="operational",
variable_of_interest: str = None,
variable_of_interest_legend: str = None,
):
"""
Returns a figure of the payload-range diagram.
The diagram contains by default only the contour but can also provide a heatmap
of the grid points, if variable_of_interest is not None.
Please note that the data for the contour are expected in the variables
`data:payload_range:{mission_name}:range` and `data:payload_range:{mission_name}:payload`.
Similarly, the data for the heatmap are expected in the variables
`data:payload_range:{mission_name}:grid:range`,
`data:payload_range:{mission_name}:grid:payload` and
`data:payload_range:{mission_name}:grid:{variable_of_interest}`.
:param aircraft_file_path: path of data file
:param name: name to give to the trace added to the figure
:param mission_name: name of the mission present in the data file to be plotted.
:param variable_of_interest: variable of interest for the heatmap.
:param variable_of_interest_legend: name to give to variable of interest in plot legend.
:return: payload-range plot figure
"""
variables = VariableIO(aircraft_file_path).read()

# Contour of the payload range
range_ = np.asarray(variables[f"data:payload_range:{mission_name}:range"].value)
payload = np.asarray(variables[f"data:payload_range:{mission_name}:payload"].value)

pr_contour = go.Scatter(
x=convert_units(range_, "m", "NM"),
y=convert_units(payload, "kg", "t"),
mode="lines+markers",
line=dict(color="black", width=3),
showlegend=False,
name=name,
)

# Create mask for a nice payload range
range_mask = np.append(range_, (1.03 * max(range_), 1.03 * max(range_), 0))
payload_mask = np.append(payload, (0, 1.1 * max(payload), 1.1 * max(payload)))

pr_contour_mask = go.Scatter(
x=convert_units(range_mask, "m", "NM"),
y=convert_units(payload_mask, "kg", "t"),
mode="lines",
line=dict(color="#E5ECF6", width=3),
showlegend=False,
name=name,
fill="toself",
fillcolor="#E5ECF6",
)

fig = go.Figure()
fig.add_trace(pr_contour_mask)
fig.add_trace(pr_contour)

if variable_of_interest is not None:
# Grid for the payload range
range_grid = np.asarray(variables[f"data:payload_range:{mission_name}:grid:range"].value)
payload_grid = np.asarray(
variables[f"data:payload_range:{mission_name}:grid:payload"].value
)
variable_of_interest_grid = np.asarray(
variables[f"data:payload_range:{mission_name}:grid:{variable_of_interest}"].value
)

variable_of_interest_unit = variables[
f"data:payload_range:{mission_name}:grid:{variable_of_interest}"
].units

if variable_of_interest_legend is None:
variable_of_interest_legend = variable_of_interest

x = convert_units(range_grid, "m", "NM")
y = convert_units(payload_grid, "kg", "t")
z = variable_of_interest_grid

min_z = min(z)
max_z = max(z)

fig.add_trace(
go.Contour(
x=x,
y=y,
z=z,
contours=dict(start=min_z, end=max_z, size=(max_z - min_z) / 20),
colorbar=dict(
title=f"{variable_of_interest_legend} [{variable_of_interest_unit}]",
titleside="right",
titlefont=dict(size=15, family="Arial, sans-serif"),
tickformat=".1e",
),
colorscale="RdBu_r",
contours_coloring="heatmap",
)
)
fig.add_trace(go.Scatter(x=x, y=y, hovertext=z, mode="markers"))

fig.update_layout(
xaxis_title="Range [NM]",
yaxis_title="Payload [tons]",
yaxis_range=[0, convert_units(max(payload_mask), "kg", "t")],
xaxis_range=[0, convert_units(max(range_mask), "m", "NM")],
showlegend=False,
height=500,
width=900,
title={"text": name, "y": 0.9, "x": 0.5, "xanchor": "center", "yanchor": "top"},
)
return fig


def _get_variable_values_with_new_units(
variables: VariableList, var_names_and_new_units: Dict[str, str]
):
Expand Down
16 changes: 16 additions & 0 deletions src/fastoad/gui/tests/data/problem_outputs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,22 @@
</main_route>
</sizing>
</mission>
<payload_range>
<sizing>
<TOW units="kg" is_input="False">[78281.31485897899, 78281.31485897899, 78281.31485897899, 64673.31485897899]</TOW>
<block_fuel units="kg" is_input="False">[0.0, 12899.912481096697, 18899.912481096697, 18899.912481096697]</block_fuel>
<duration units="s" is_input="False">[[0.0], [14098.555141498835], [24041.003137592204], [30872.771086026758]]</duration>
<payload units="kg" is_input="False">[19608.0, 19608.0, 13608.0, 0.0]</payload>
<range units="m" is_input="False">[[0.0], [3146451.370616018], [5436689.798019956], [7019409.601837909]]</range>
<grid>
<TOW units="kg" is_input="False">[73290.20099565906, 70107.94693864312, 74855.15092378357, 73414.34933881543, 74016.1942793167, 66271.39924130478, 70444.4618586155, 71940.03089616474, 63392.24510815984, 71458.58111584073, 66984.13676542982, 76364.63682260923, 72107.33665317285, 69137.75207548637, 73823.65802758957, 62967.93168111551, 73984.64393726233, 77492.05533442025, 67062.17507141, 69340.66800283235, 71296.60372064878, 66283.86957245003, 70349.59134154848, 76526.56997665859, 70713.7101024175, 66523.87413057004, 74035.22764118905, 77153.64730643228, 68209.00495432317, 68351.1875510712, 73394.63946343679, 66747.41602366594, 75597.78926372367, 74767.05251716073, 66607.68815289404, 78134.67960613786, 65564.04842121096, 63998.29492421057, 60684.48024548951, 67766.72828131466, 71688.09865703632, 71122.42676942382, 71802.76236589532, 67611.8239704066, 69761.58090230104, 58862.93390150307, 59442.372538136275, 70799.57909768244, 73517.21273896092, 61555.025408844085]</TOW>
<block_fuel units="kg" is_input="False">[14831.938038565362, 5593.735170781555, 18103.921845192013, 9454.242102985505, 12569.481847485324, 9018.170523314557, 10457.56128790164, 9804.801575686917, 7286.288316421167, 13357.73840292843, 7997.582664520765, 12744.498858948069, 16882.352079957014, 9757.06676949321, 11827.471713911289, 8182.615966306898, 17568.827747203377, 18383.33377455142, 8401.755103500527, 11758.244210522013, 7194.889776298828, 5615.865004923188, 14322.07306853182, 16282.98995977861, 18211.52379123202, 5771.365267457352, 9188.030530168244, 15614.975713884829, 15053.679525080122, 15440.253000391926, 8597.72188441914, 8804.866736061354, 15713.071537772901, 11611.609982470985, 13237.24536789392, 14817.3517896359, 9955.52670223676, 11547.037853119513, 6531.86627859634, 15800.345945665307, 6479.463972487137, 8401.730869395129, 9269.509794047517, 12558.935866015958, 15714.784534717688, 7046.7225664617545, 5707.834621195616, 9725.442290721214, 16547.66884535385, 6948.570135977641]</block_fuel>
<duration units="s" is_input="False">[[19001.560446718995], [3195.5043437465447], [24097.164041604214], [9453.910645153906], [14556.983184909399], [9947.204600935198], [11679.853941744992], [10284.655157607127], [7034.971242130049], [16742.19562012445], [7819.639518628751], [14415.87875182012], [23112.87879243148], [10764.480427898285], [13315.838392397376], [8907.000558068583], [23367.480100024517], [23360.520933402964], [8562.212537352592], [14464.70817890859], [5836.4038375649925], [3511.4572359433423], [18774.67567593142], [20444.880185716524], [26047.402182310405], [3779.5374138850075], [8820.020268557086], [19135.427329705697], [21115.565217174913], [21840.91624602035], [7992.373658927233], [9457.118978644698], [19677.333389633943], [12787.624346045772], [18242.089046570494], [17253.248988806234], [11908.812938532308], [15444.818116864495], [5865.74176852227], [22727.185357359434], [4580.277275290412], [7943.8357887065185], [9367.79136816222], [16377.607416838893], [21969.350322699993], [7200.277959980638], [4275.482107894924], [10317.157285723888], [22088.65914624892], [6589.775053972623]]</duration>
<payload units="kg" is_input="False">[12684.860579211409, 18740.80938997927, 10977.826700709264, 18186.704857947636, 15673.310053949082, 11479.826340107938, 14213.498192831561, 16361.826942595531, 10332.55441385638, 12327.440335029996, 13213.151723026765, 17846.73558577886, 9451.582195333549, 13607.282928110859, 16222.783935795987, 9011.913336926315, 10642.413812176652, 13335.31918198653, 12887.017590027184, 11809.021414428036, 18328.311566467662, 14894.602189644545, 10254.115895134373, 14470.17763899769, 6728.783933303198, 14979.106485230399, 19073.794733138508, 15765.269214665148, 7381.923051360759, 7137.532172796976, 19023.515201135346, 12169.146909722285, 14111.315348068465, 17382.040156807445, 7597.040407117826, 17543.92543861965, 9835.119341091899, 6677.854693208758, 8379.211589010878, 6192.979957767064, 19435.23230666689, 16947.293522146403, 16759.850193965507, 9279.485726508348, 8273.39398970105, 6042.808957159024, 7961.135539058366, 15300.734429078917, 11196.141515724774, 8833.052894984152]</payload>
<range units="m" is_input="False">[[4277509.049862042], [639973.9201204008], [5450039.685016667], [2078910.5486571286], [3253534.431429572], [2197182.1821120675], [2593337.609939235], [2271086.320906983], [1528548.2553895472], [3758473.3687609523], [1706706.9559890365], [3219555.7508331845], [5225331.15602352], [2383400.1222222107], [2967869.2428306774], [1960064.574292493], [5282631.028763698], [5280480.511261459], [1877665.911439978], [3235425.907581472], [1247300.5831194983], [715055.4802024142], [4227421.500731071], [4607684.042694435], [5902466.449513065], [776630.2044571321], [1932625.4282768501], [4305728.044593988], [4768256.132325516], [4935237.443700671], [1742440.1373497848], [2083966.7616859567], [4431570.651150721], [2845653.1873528957], [4107540.697719124], [3873131.998252005], [2649514.9498783625], [3465291.939641652], [1261322.6802165017], [5139900.662874845], [957888.7644393793], [1732618.1824002338], [2060061.448963879], [3677318.5744845904], [4963679.588338788], [1570254.7918785026], [896013.3530954972], [2279302.6974806227], [4988344.768924016], [1427421.5215317954]]</range>
</grid>
</sizing>
</payload_range>
<weight>
<aircraft>
<MFW units="kg">20484.57182260099<!--maximum fuel weight--></MFW>
Expand Down
31 changes: 31 additions & 0 deletions src/fastoad/gui/tests/test_analysis_and_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
mass_breakdown_bar_plot,
mass_breakdown_sun_plot,
wing_geometry_plot,
payload_range_plot,
)

DATA_FOLDER_PATH = pth.join(pth.dirname(__file__), "data")
Expand Down Expand Up @@ -123,3 +124,33 @@ def test_mass_breakdown_sun_plot():
# This is a rudimentary test as plot are difficult to verify
# The test will fail if an error is raised by the following line
_ = mass_breakdown_sun_plot(filename)


def test_payload_range_plot():
"""
Basic tests for testing the plotting.
"""

filename = pth.join(DATA_FOLDER_PATH, "problem_outputs.xml")

# First plot
# This is a rudimentary test as plot are difficult to verify
# The test will fail if an error is raised by the following line
# Only contour
fig = payload_range_plot(
filename,
name="Payload-Range",
mission_name="sizing",
variable_of_interest=None,
variable_of_interest_legend=None,
)

# Second plot
# With grid
fig = payload_range_plot(
filename,
name="Payload-Range",
mission_name="sizing",
variable_of_interest="block_fuel",
variable_of_interest_legend="Block fuel",
)

0 comments on commit 2b40991

Please sign in to comment.