Source code for materials.plot_utils

"""Material Property plotting utilities."""

import numpy as np
from matplotlib import pyplot as plt


[docs]def plot_property_vs_state(prop, state_model=None, state_name=None, state_range=None, value_for_other_state=None, axes=None, **pyplot_kwargs): """Plot a state-dependent property. Arguments: prop (Property): The property to plot. state_model (string): The name of the state model to plot from (i.e. a key of `variations_with_state`) state_name (string): Name of the state variable to plot the property value against. state_range (tuple of length 2): Range of state variable values to plot over (low, high). value_for_other_state (scalar): If the property depends on two states, fix the other state at this value. axes (matplotlib.axes.Axes): Axes to plot on. Makes a new figure if `axes` is None. Other keyword arguments are passed to `pyplot.plot`. Returns: matplotlib.axes.Axes: The axes on which the plot was drawn. """ if state_model is None: state_model = prop.default_state_model if state_model not in prop.variations_with_state: raise ValueError('Property {:s} does not have a variation with state model named {:s}'.format( prop.name, state_model)) if state_name is None: state_name = prop.variations_with_state[state_model].state_vars[0] if len(prop.variations_with_state[state_model].state_vars) > 1 and value_for_other_state is None: raise ValueError('Property depends on more than one state. Must provide value_for_other_state.') if len(prop.variations_with_state[state_model].state_vars) == 1 and value_for_other_state is not None: raise ValueError('Property only depends on one state, do not provide value_for_other_state.') if state_name not in prop.variations_with_state[state_model].state_vars: raise ValueError('Property does not have a state variable named {:s}'.format(state_name)) if state_range is None: state_range = prop.variations_with_state[state_model].get_state_domain()[state_name] if axes is None: plt.figure() axes = plt.axes() states = np.linspace(state_range[0], state_range[1]) query = {state_name: states} if value_for_other_state is not None: other_state_name = (set(prop.state_vars) - set((state_name,))).pop() query[other_state_name] = np.full_like(states, value_for_other_state) values = prop.query_value(query, state_model) axes.plot(states, values, **pyplot_kwargs) axes.set_xlabel('{:s} [{:s}]'.format( state_name, prop.variations_with_state[state_model].state_vars_units[state_name])) axes.set_ylabel('{:s} [{:s}]'.format( prop.name.replace('_', ' '), prop.units)) return axes
[docs]def decorate_temperature_axis(axes, temperature_range=(0, np.inf), comparison_set='space propulsion'): """ Decorate temperature axis with comparison temperatures. References: .. [1] Lozano, Paulo, "Monopropellant Thrusters", 16.522 Notes, MIT.\n Online: https://ocw.mit.edu/courses/aeronautics-and-astronautics/16-522-space-propulsion-spring-2015/lecture-notes/MIT16_522S15_Lecture12.pdf .. [2] Sutton, George P and Oscar Biblarz, Rocket Propulsion Elements, 8th ed., 2010. .. [3] US Department of Defense, "Global Climatic Data for Developing Military Products", MIL-HDBK-310, 1997. """ temperature_comparisons = { 'space propulsion': { 20.28: 'hydrogen boils', 90.2: 'oxygen boils', 111.67: 'methane boils', 273.15 + 25: 'room temp.', 1100: 'typ. gas generator', # see [2], table 5-10. 1343: 'hydrazine flame', # Assuming 40% NH3 decomposed, see [1] 3389: '$H_2 + O_2$ flame' # Mass oxid/fuel ratio = 5.55, see [2] }, 'weather': { 184: 'Earth record cold', 273.15: 'water freezes', 273.15 + 25: 'room temp.', 273.15 + 70.7: 'Earth record high', 273.15 + 100: 'water boils', }, 'aviation': { 199: 'cold day, 10 km alt.', # 1% cold day, see [3] table 5.3.2.2.2 273.15 + 25: 'room temp.', 273.15 + 49: 'hot day, desert', # 1% hot day, Saharah desert, see [3] sec. 5.1.1.2 278 * (1 + 0.2 * 2 ** 2): '$T_{stag}$ at Mach 2', # 1% hot day at 5 km alt, see [3] 278 * (1 + 0.2 * 3 ** 2): '$T_{stag}$ at Mach 3', 278 * (1 + 0.2 * 4 ** 2): '$T_{stag}$ at Mach 4', 278 * (1 + 0.2 * 5 ** 2): '$T_{stag}$ at Mach 5', 278 * (1 + 0.2 * 6 ** 2): '$T_{stag}$ at Mach 6', 273.15 + 2093: 'kerosene + air flame', } } annotation_color = (0.4, 0.4, 0.4) if comparison_set not in temperature_comparisons: raise ValueError( '{:s} is not an available temperature comparison set.' + 'Available comparison sets:\n' + ''.join(['\t{:s}\n'.format(s) for s in temperature_comparisons])) for temperature, comparison_text in temperature_comparisons[comparison_set].items(): if temperature_range[0] < temperature < temperature_range[1]: axes.axvline(temperature, color=annotation_color) text_y = 0.1 * (axes.get_ylim()[1] - axes.get_ylim()[0]) + axes.get_ylim()[0] text_x = temperature axes.text(text_x, text_y, comparison_text, rotation=90, color=annotation_color, horizontalalignment='center', verticalalignment='bottom', bbox={'facecolor': 'white', 'alpha': 0.9, 'edgecolor': 'none', 'pad': 3})