Source code for RCAIDE.Library.Plots.Emissions.plot_contrails_appleman_chart

# RCAIDE/Library/Plots/Emissions/plot_contrails_appleman_chart
# 
# 
# Created:  Jul 2024, M. Clarke

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------  
from RCAIDE.Framework.Core import Units
from RCAIDE.Library.Plots.Common import set_axes, plot_style 
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np 

# ----------------------------------------------------------------------------------------------------------------------
#  PLOTS
# ----------------------------------------------------------------------------------------------------------------------   
## @ingroup Library-Plots-Performance-Emissions 
[docs] def plot_contrails_appleman_chart(results, save_figure = False, show_legend = True, save_filename = "Appleman_Chart" , file_type = ".png", width = 8, height = 6): """ Generate plots showing CO2-equivalent emissions and emission indexes for various fuel species over mission segments. Parameters ---------- results : Data Mission results data structure containing: results.segments[i].conditions.emissions.total with fields: - CO2 : array Carbon dioxide emissions [kg] - NOx : array Nitrogen oxide emissions [kg] - H2O : array Water vapor emissions [kg] - Contrails : array Contrail formation impact [kg CO2e] - Soot : array Particulate emissions [kg] - SO2 : array Sulfur dioxide emissions [kg] save_figure : bool, optional Save figure to file if True, default False show_legend : bool, optional Display segment legend if True, default True save_filename : str, optional Name for saved figure file, default "CO2e_Emissions" file_type : str, optional File extension for saved figure, default ".png" width : float, optional Figure width in inches, default 11 height : float, optional Figure height in inches, default 7 Returns ------- fig : matplotlib.figure.Figure Figure showing stacked emissions contributions Notes ----- Creates a stacked area plot showing: - Individual contributions from each emission type - Cumulative total CO2-equivalent impact - Breakdown by mission segment - Time history of emissions Different emission types are distinguished by fill colors and segments use different shades from the inferno colormap. **Definitions** 'CO2-equivalent (CO2e)' Combined climate impact normalized to CO2 'Global Warming Potential (GWP)' Relative impact factor for different emissions 'Contrail Impact' Climate forcing from aviation-induced cloudiness """ # get plotting style ps = plot_style() parameters = {'axes.labelsize': ps.axis_font_size, 'xtick.labelsize': ps.axis_font_size, 'ytick.labelsize': ps.axis_font_size, 'axes.titlesize': ps.title_font_size} plt.rcParams.update(parameters) fig = plt.figure(save_filename) fig.set_size_inches(width,height) line_colors = cm.inferno(np.linspace(0,0.9,len(results.segments))) # always contrains left of line always_contrails_line = np.array([[-59.43367168358419, 101.16672500291688], [-55.971298564928254, 149.10512192276286], [-53.23976198809942, 202.20977715552448], [-51.07478707268698, 254.72173608680438], [-48.994516392486304, 316.4531559911329], [-46.60133006650334, 405.2829308132073], [-44.84984249212462, 479.10862209777156], [-44.453622681134064, 500.4456889511142]]) maximum_T_for_persistence_line = np.array([[-56.842608797106536, 101.24139540310355], [-54.4251545910629, 130.12950647532384], [-52.33321666083305, 163.0428188076071], [-50.644965581612425, 193.0626531326567], [-49.120289347800735, 227.11235561778093], [-47.59607980399021, 262.314782405787], [-45.83479173958699, 311.93326332983315], [-44.31361568078405, 354.628398086571], [-43.59584645898963, 381.73842025434607], [-41.52140940380353, 457.87889394469727], [-40.9651149224128, 483.83152490957883], [-40.64753237661884, 499.40263679850665]]) # no contrails right of line no_contrails_line = np.array([[-50.76957181192394, 100.84004200210016], [-48.83514175708787, 122.79780655699457], [-45.85649282464124, 165.53494341383742], [-43.44603896861511, 211.71391902928485], [-41.35970131839927, 258.4599229961499], [-40.39878660599698, 285.0005833625015], [-38.638431921596094, 336.9245128923113], [-36.80200676700503, 400.95438105238594], [-35.366468323416186, 455.17442538793614], [-34.2513125656283, 500.73970365184925]]) # An Appleman chart can be used to identify more and less favorable conditions. Using the vehicle's mission, estimate the # time the vehicle will spend at a lower temperature and/or higher pressure than the 0% relative humidity on the Appleman chart. # Also use the vehicle's mission, estimate the time the vehicle will spend at temperatures and pressures # between the 0% relative humidity and maximum temperature for persistence on the Appleman chart. # plot bounds of Appleman chart axis = fig.add_subplot(1, 1, 1) axis.plot(always_contrails_line[:,0], always_contrails_line[:,1], label = "Always Contrails", linewidth = ps.line_width, linestyle = '-', color = 'black') axis.plot(maximum_T_for_persistence_line[:,0], maximum_T_for_persistence_line[:,1], label = "Maximum T for Persistence", linewidth = ps.line_width, color = 'black', linestyle = '--') axis.plot(no_contrails_line[:,0], no_contrails_line[:,1], label = "No Contrails", linewidth = ps.line_width, color = 'black', linestyle = ':') axis.set_xlabel('Temperature (°C)') axis.set_ylabel('Pressure (hPa)') axis.set_ylim(100,500) axis.set_xlim(-60,-30) axis.invert_yaxis() # start with 0 time in each region always_contrails_time_sec =0 persistence_time_sec = 0 # get line colors for plots line_colors = cm.inferno(np.linspace(0,0.9,len(results.segments))) # loop through mission segments and plot conditions on Appleman chart for i in range(len(results.segments)): always_contrails_time_stamps = [] persistence_time_stamps = [] no_contrails_time_stamps = [] T = results.segments[i].conditions.freestream.temperature[:,0] - 273.15 P = results.segments[i].conditions.freestream.pressure[:,0]/100 t = results.segments[i].conditions.frames.inertial.time[:,0] # rediscretize temperature pressure and time to ensure points are captured within appleman chart time = np.linspace(t[0], t[-1], 200) temperature = np.interp(time, t, T) pressure = np.interp(time, t, P) segment_tag = results.segments[i].tag segment_name = segment_tag.replace('_', ' ') # if any of the pressure values are above 500 hPa, print a warning that the conditions are outside the bounds of the Appleman chart if np.any(pressure < 500): axis.scatter(temperature, pressure, label =segment_name, color = line_colors[i], s = 50) # compute time spent in each region based in temperature and pressure conditions for j in range(len(temperature)): if temperature[j] < np.interp(pressure[j], always_contrails_line[:,1], always_contrails_line[:,0]): always_contrails_time_stamps.append(time[j]) if temperature[j] > np.interp(pressure[j], no_contrails_line[:,1], no_contrails_line[:,0]): no_contrails_time_stamps.append(time[j]) # compute time spent between 0% relative humidity (always contrails) and maximum temperature for persistence on the Appleman chart if temperature[j] > np.interp(pressure[j], always_contrails_line[:,1], always_contrails_line[:,0]) and temperature[j] < np.interp(pressure[j], maximum_T_for_persistence_line[:,1], maximum_T_for_persistence_line[:,0]): persistence_time_stamps.append(time[j]) # convert time stamps into numpy arrays and compute total time spent in each region always_contrails_time_stamps = np.array(always_contrails_time_stamps) persistence_time_stamps = np.array(persistence_time_stamps) no_contrails_time_stamps = np.array(no_contrails_time_stamps) # use differences between time stamps to compute total time spent in each region always_contrails_time_sec += np.sum(np.diff(always_contrails_time_stamps)) persistence_time_sec += np.sum(np.diff(persistence_time_stamps)) else: print(segment_name + "Segment has pressure values outside the bounds of the Appleman chart. Time spent in each region may be inaccurate.") # add annotations for each region of the Appleman chart axis.text(-58, 400, 'Always Contrails', fontsize = 12 , color = 'black') axis.text(-50, 220, 'Maybe Contrails', fontsize = 12 , color = 'black') axis.text(-38, 150, 'No Contrails', fontsize = 12 , color = 'black') t_fin = results.segments[-1].conditions.frames.inertial.time[-1,0] no_contrails_time_sec = t_fin - always_contrails_time_sec - persistence_time_sec # percent of flight in each regine always_contrails_time_percent = (always_contrails_time_sec/t_fin)*100 persistence_time_percent = (persistence_time_sec/t_fin)*100 no_contrails_time_percent = (no_contrails_time_sec/t_fin)*100 print(f"Percent of flight in Always Contrails region: {always_contrails_time_percent:.2f}%") print(f"Percent of flight in Persistence region: {persistence_time_percent:.2f}%") print(f"Percent of flight in No Contrails region: {no_contrails_time_percent:.2f}%") always_contrails_time_hr = always_contrails_time_sec/3600 persistence_time_hr = persistence_time_sec/3600 no_contrails_time_hr = no_contrails_time_sec/3600 # time spend in each region print(f"Time spent in Always Contrails region: {always_contrails_time_hr:.2f} hours") print(f"Time spent in Persistence region: {persistence_time_hr:.2f} hours") print(f"Time spent in No Contrails region: {no_contrails_time_hr:.2f} hours") if show_legend: leg = fig.legend(bbox_to_anchor=(0.5, 0.95), loc='upper center', ncol = 4) leg.set_title('Flight Segment', prop={'size': ps.legend_font_size, 'weight': 'heavy'}) # Adjusting the sub-plots for legend # set title of plot title_text = 'Appleman Chart' fig.tight_layout() fig.suptitle(title_text) fig.subplots_adjust(top=0.8) if save_figure: plt.savefig(save_filename + file_type) return fig