#!/usr/bin/env python # coding: utf-8 # **CRIB SHEET RULES OF THE ROAD:** # # This crib sheet is provided to support access, utilization, and plotting of UCalgary optical datasets and models. It is intended as a base set of code that a user may edit and manipulate to serve their own needs. Crib sheets contains UCalgary verified and validated procedures for plotting and manipulating UCalgary ASI data and models for common use cases. Use of this crib sheet does not require acknowledgment, it is freely distributed for scientific use. Please also remember to perform due diligence on all data use. We recommend comparison with verified data products on [data.phys.ucalgary.ca](https://data.phys.ucalgary.ca) to ensure that any user output does not contradict operational summary plots. Data use must be acknowledged according to the information available for each data set - please see [data.phys.ucalgary.ca](https://data.phys.ucalgary.ca). If you encounter any issues with the data or the crib sheet, please contact the UCalgary team for support (Emma Spanswick, elspansw@ucalgary.ca). Copyright © University of Calgary. # --- # # **TREx Auroral Transport Model** # --- # # TREx-ATM is a time-dependent Aurora Transport Model (ATM), designed to leverage and support TREx optical data. TREx-ATM uses the two-stream electron transport code embedded in the GLOW model (Solomon et al., 1988) with ambipolar diffusion to compute the electron transport. It has additional capacity to compute impact ionization, secondary electron production, and impact excitation of neutrals (height resolved). Use of the TREx-ATM model should cite: # # *Liang, J., Donovan, E., Jackel, B., Spanswick, E., & Gillies, M. (2016). On the 630nmred-linepulsating aurora: Red-line emission geospace observatory observations and model simulations. Journal of Geophysical Research: Space Physics, 121, 7988–8012. https://doi.org/10.1002/2016JA022901* # # *Liang, J., Yang, B., Donovan, E., Burchill, J., & Knudsen, D. (2017). Ionospheric electron heating associated with pulsating auroras: A Swarm survey and model simulation. Journal of Geophysical Research: Space Physics, 122, 8781–8807. https://doi.org/10.1002/2017JA024127* # # # ### **Crib Sheet Summary** # Below are examples of using PyAuroraX to perform a TREx Auroral Transport Model (ATM), forward and inverse calculations. # # #
# # --- # #
# # # ## **Install dependencies** # # Here we'll install [PyAuroraX](https://github.com/aurorax-space/pyaurorax), and import it. # # Some helpful links: # - [PyAuroraX documentation](https://docs.aurorax.space/code/overview) # - [PyAuroraX API Reference](https://docs.aurorax.space/code/pyaurorax_api_reference/pyaurorax) # - [Jupyter notebook examples](https://github.com/aurorax-space/pyaurorax/tree/main/examples/notebooks) # In[ ]: get_ipython().system('pip install pyaurorax') # In[ ]: import datetime import numpy as np import matplotlib.pyplot as plt import pyaurorax aurorax = pyaurorax.PyAuroraX() # ## **Forward Calculations** # ### **Perform a basic 'forward' calculation** # # First will show how to do a basic request, and plot the results. Later on, we'll show how to do a request by supplying a custom spectrum. # # Requests take a series of input parameters. Some parameters are required, and some are optional with default values that will be set if they are not supplied. The following request we'll be performing utilizes all default values for the optional parameter (marked as such with a comment on that line). # # More details on inputs and outputs [in the `forward()` function documentation](https://docs.aurorax.space/code/pyaurorax_api_reference/pyaurorax/models/atm/index.html#pyaurorax.models.atm.ATMManager.forward). # # # Input notes: # # - latitude and longitude are to be in geodetic coordinates (-90 to 90 lat, -180 to 180 lon) # - maxwellian_characteristic_energy must be specified if the maxwellian_energy_flux is not 0 # - gaussian_peak_energy must be specified if the gaussian_energy_flux is not 0 # - gaussian_spectral_width must be specified if the gaussian_energy_flux is not 0 # - valid values for nrlmsis_model_version are '00' and '2.0' # - units # - timescale parameters: seconds # - maxwellian energy flux: erg/cm2/s # - maxwellian characteristic energy: eV # - gaussian energy flux: erg/cm2/s # - gaussian peak energy: eV # - gaussian spectral width: eV # - custom spectrum # - energy in eV, flux in 1/cm2/sr/eV # - energy and flux arrays must be the same length # # # # Output notes: # # - output parameter of the request are toggles the enable/disable each field's inclusion in the response # - all output parameters are false by default # - altitude is in kilometers # - emission data: 1-D array -- volume emission rate (1/cm^3/s) # - plasma electron density: 1-D array -- density (cm^-3) # - plasma O2+ density: 1-D array -- density (cm^-3) # - plasma NO+ density: 1-D array -- density (cm^-3) # - plasma O+ density: 1-D array -- density (cm^-3) # - plasma ionisation rate: 1-D array -- ionisation rate (1/cm^3/s) # - plasma electron temperature: 1-D array -- temperature (K) # - plasma ion temperature: 1-D array -- temperature (K) # - plasma peterson conductivity: 1-D array -- conductivity (S/m) # - plasma hall conductivity: 1-D array -- conductivity (S/m) # - neutral O2 density: 1-D array -- density (cm^-3) # - neutral O density: 1-D array -- density (cm^-3) # - neutral N2 density: 1-D array -- density (cm^-3) # - neutral N density: 1-D array -- density (cm^-3) # - neutral temperature: 1-D array -- temperature (K) # # ATM requests require that users toggle ON outputs they wish to have returned. This allows you to get back only what you want. This mechanism is controlled by the `ATMForwardOutputFlags()` class that must be instantiated before making an ATM calculation. # # As part of this class, there are helper functions that toggle ON or OFF all outputs, and toggle on common groups. # In[ ]: # set up our request # # all output parameters are default to False. Here we initialize # the output flags we want to get output = pyaurorax.models.ATMForwardOutputFlags() # initialize output flags, all will be False by default output.enable_only_height_integrated_rayleighs() # enable all height-integrated Rayleighs values output.altitudes = True # enable altitudes output.emission_5577 = True # enable the 5577nm emission # set the location (Calgary-ish) # # NOTE: ATM forward calculations can be performed # for any latitude or longitude latitude = 51.04 longitude = -114.5 # set the timestamp to UT06 of the previous day # # NOTE: ATM forward calculations can be performed for any date up # to the end of the previous day. It is expected to be in UTC time, # and any timezone data will be ignored. timestamp = datetime.datetime.now().replace(hour=6, minute=0, second=0, microsecond=0) - datetime.timedelta(days=1) # In[ ]: # perform the calculation result = aurorax.models.atm.forward(timestamp, latitude, longitude, output) # view the output # # we use handy print method for the results result.pretty_print() # Let's have a closer look at some of the results. # In[ ]: # plot the 557.7nm emission data plt.title("557.7nm emission") plt.xlabel("Volume emission rate (1/cm^3/s)") plt.ylabel("Altitude (km)") plt.plot(result.emission_5577, result.altitudes) plt.show() # ### **Perform a request by supplying a custom spectrum** # # You can also perform requests by supplying a custom spectrum. Below, we'll do this using some example spectrum data. Note that the energy and flux arrays must be the same length, and energy and flux values are to be floats in eV and 1/cm2/sr/eV, respectively. # In[ ]: # two arrays that we'll merge into a Nx2 numpy array, representing energy and flux. custom_spectrum_energy = [ 1.25000, 1.75000, 2.25000, 2.75000, 3.25000, 3.75000, 4.25000, 4.75000, 5.25000, 5.75000, 6.25000, 6.75000, 7.25000, 7.75000, 8.25000, 8.75000, 9.25000, 9.75000, 10.2500, 10.7616, 11.3058, 11.8854, 12.4948, 13.1354, 13.8089, 14.5169, 15.2612, 16.0436, 16.8662, 17.7310, 18.6401, 19.5957, 20.6004, 21.6566, 22.7670, 23.9343, 25.1614, 26.4515, 27.8077, 29.2334, 30.7322, 32.3079, 33.9644, 35.7058, 37.5365, 39.4610, 41.4842, 43.6111, 45.8471, 48.1978, 50.6689, 53.2668, 55.9978, 58.8689, 61.8871, 65.0602, 68.3959, 71.9026, 75.5891, 79.4647, 83.5389, 87.8221, 92.3248, 97.0584, 102.035, 107.266, 112.766, 118.547, 124.625, 131.015, 137.732, 144.794, 152.218, 160.022, 168.227, 176.852, 185.919, 195.452, 205.473, 216.007, 227.082, 238.725, 250.965, 263.832, 277.359, 291.579, 306.529, 322.245, 338.767, 356.136, 374.395, 393.591, 413.771, 434.985, 457.288, 480.733, 505.381, 531.292, 558.532, 587.169, 617.274, 648.922, 682.193, 717.170, 753.940, 792.595, 833.232, 875.953, 920.864, 968.078, 1017.71, 1069.89, 1124.75, 1182.41, 1243.04, 1306.77, 1373.77, 1444.20, 1518.25, 1596.09, 1677.92, 1763.95, 1854.39, 1949.47, 2049.42, 2154.50, 2264.96, 2381.09, 2503.17, 2631.51, 2766.43, 2908.27, 3057.38, 3214.13, 3378.93, 3552.17, 3734.29, 3925.75, 4127.03, 4338.63, 4561.07, 4794.92, 5040.76, 5299.21, 5570.91, 5856.53, 6156.80, 6472.47, 6804.32, 7153.18, 7519.93, 7905.49, 8310.81, 8736.92, 9184.87, 9655.7 ] custom_spectrum_flux = [ 14237.8, 19932.9, 25628.1, 31323.2, 37018.3, 42713.4, 48408.6, 54103.7, 59798.8, 65493.9, 71189.1, 76884.2, 82579.3, 88274.4, 93969.6, 99664.7, 105360.0, 111055.0, 116750.0, 122577.0, 128775.0, 135378.0, 142319.0, 149616.0, 157287.0, 165351.0, 173829.0, 182741.0, 192110.0, 201960.0, 212315.0, 223200.0, 234644.0, 246675.0, 259322.0, 272618.0, 286595.0, 301289.0, 316737.0, 332976.0, 350048.0, 367995.0, 386863.0, 406698.0, 427550.0, 449471.0, 472515.0, 496742.0, 522210.0, 548985.0, 577132.0, 606722.0, 637829.0, 670531.0, 704910.0, 741052.0, 779046.0, 818989.0, 860979.0, 905122.0, 951529.0, 1.00032e+06, 1.05160e+06, 1.10552e+06, 1.14681e+06, 1.16681e+06, 1.18332e+06, 1.19597e+06, 1.20452e+06, 1.21134e+06, 1.21518e+06, 1.21786e+06, 1.21958e+06, 1.22031e+06, 1.21912e+06, 1.21596e+06, 1.21029e+06, 1.20159e+06, 1.18984e+06, 1.17542e+06, 1.15883e+06, 1.14056e+06, 1.12111e+06, 1.10084e+06, 1.07960e+06, 1.05717e+06, 1.03333e+06, 1.00787e+06, 980597.0, 951507.0, 920731.0, 888359.0, 854453.0, 819049.0, 782220.0, 744214.0, 705369.0, 665934.0, 626276.0, 586707.0, 547469.0, 508787.0, 470923.0, 434073.0, 398475.0, 364314.0, 331712.0, 300753.0, 271519.0, 244145.0, 218704.0, 195202.0, 173623.0, 153886.0, 135967.0, 119819.0, 105375.0, 92493.0, 81018.5, 70809.4, 61716.9, 53608.8, 46394.7, 40017.3, 34425.8, 29569.1, 25398.0, 21855.1, 18852.0, 16295.5, 14096.6, 12167.9, 10429.6, 8852.41, 7439.90, 6196.57, 5126.73, 4235.10, 3517.08, 2944.53, 2486.98, 2115.25, 1801.38, 1520.12, 1263.38, 1033.71, 833.682, 665.821, 532.604, 433.682, 362.035, 310.022, 270.400, 236.311, 201.652, 165.385 ] custom_spectrum_arr = np.empty((len(custom_spectrum_energy), 2), dtype=np.float64) custom_spectrum_arr[:, 0] = np.asarray(custom_spectrum_energy)[:] custom_spectrum_arr[:, 1] = np.asarray(custom_spectrum_flux)[:] # In[ ]: # set parameters timestamp = datetime.datetime(2021, 11, 4, 6, 0, 0) latitude = 58.227808 longitude = -103.680631 # set output output = pyaurorax.models.ATMForwardOutputFlags() output.altitudes = True output.plasma_electron_density = True # perform the calculation result = aurorax.models.atm.forward(timestamp, latitude, longitude, output) # In[ ]: # plot the electron density data plt.title("Electron Density") plt.xlabel("Density (cm^-3)") plt.ylabel("Altitude (km)") plt.plot(result.plasma_electron_density, result.altitudes) plt.show() # ### **Do a request with all output parameters** # # You can also do a request and specify the output flags to return everything that the ATM 'forward' endpoint has to offer. Below, we're going to do that and plot all data. # In[ ]: timestamp = datetime.datetime(2021, 11, 4, 6, 0, 0) latitude = 58.227808 longitude = -103.680631 output = pyaurorax.models.ATMForwardOutputFlags() output.set_all_true() result = aurorax.models.atm.forward(timestamp, latitude, longitude, output) result.pretty_print() # In[ ]: # let's show everything we got back # # print all height-integrated Rayleighs data print("""Height-integrated Rayleighs: 427.8nm: %.02f R 557.7nm: %.02f R 630.0nm: %.02f R 844.6nm: %.02f R LBH: %.02f R 130.4nm: %.02f R 135.6nm: %.02f R""" % (result.height_integrated_rayleighs_4278, result.height_integrated_rayleighs_5577, result.height_integrated_rayleighs_6300, result.height_integrated_rayleighs_8446, result.height_integrated_rayleighs_lbh, result.height_integrated_rayleighs_1304, result.height_integrated_rayleighs_1356)) # plot the emission, plasma, and neutral data # # we'll do this all in one plot, but made up from many subplots alt = result.altitudes fig = plt.figure(figsize=(9,9)) # plot all the emissions as a column of subplots # # 1304 A & 1356 A emission ax1 = fig.add_subplot(6,2,1) ax1.plot(alt, result.emission_1304, label=r"1304 $\AA$", color="purple") ax1.plot(alt, result.emission_1356, label=r"1356 $\AA$", color="hotpink") ax1.legend() ax1.set_xlim(80,500) ax1.set_ylim(bottom=0) ax1.grid(axis="x") ax1.set_xlabel("Altitude (km)", va="bottom") ax1.tick_params(axis="x", bottom=True, top=True, labeltop=True, labelbottom=False) ax1.xaxis.set_label_position("top") # blueline emission ax2 = fig.add_subplot(6,2,3) ax2.plot(alt, result.emission_4278, label=r"4278 $\AA$", color="dodgerblue") ax2.legend() ax2.set_xlim(80,500) ax2.set_ylim(bottom=0) ax2.grid(axis="x") ax2.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # greenline emission ax3 = fig.add_subplot(6,2,5) ax3.plot(alt, result.emission_5577, label=r"5577 $\AA$", color="green") ax3.legend() ax3.set_xlim(80,500) ax3.set_ylim(bottom=0) ax3.grid(axis="x") ax3.set_ylabel("Volume Emission Rate\n(cm$^{-3} \cdot $s$^{-1}$)") ax3.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # redline emission ax4 = fig.add_subplot(6,2,7) ax4.plot(alt, result.emission_6300, label=r"6300 $\AA$", color="red") ax4.legend() ax4.set_xlim(80,500) ax4.set_ylim(bottom=0) ax4.grid(axis="x") ax4.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # near-infrared 8446 A emission ax5 = fig.add_subplot(6,2,9) ax5.plot(alt, result.emission_8446, label=r"8446 $\AA$", color="blueviolet") ax5.legend() ax5.set_xlim(80,500) ax5.set_ylim(bottom=0) ax5.grid(axis="x") ax5.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # Lyman-Birge-Hopfield emission ax6 = fig.add_subplot(6,2,11) ax6.plot(alt, result.emission_lbh, label="LBH Emission", color="indigo") ax6.legend() ax6.set_xlim(80,500) ax6.set_ylim(bottom=0) ax6.grid(axis="x") ax6.set_xlabel("Altitude (km)") ax6.tick_params(axis="x", bottom=True, top=True) # plot the plasma data as a second column of subplots # # plasma density ax7 = fig.add_subplot(4,2,2) ax7.plot(alt, result.plasma_electron_density, label="Electron", color="green") ax7.plot(alt, result.plasma_o2plus_density, label="O$^{2+}$", color="black") ax7.plot(alt, result.plasma_noplus_density, label="NO$^{+}$", color="blue") ax7.plot(alt, result.plasma_oplus_density, label="O$^{+}$", color="red") ax7.grid() ax7.set_ylabel("Plasma Density\n(cm$^{-3}$)") ax7.legend(fontsize=9) ax7.set_xlim(80,700) ax7.set_ylim(bottom=0) ax7.tick_params(axis="x", bottom=True, top=True, labeltop=True, labelbottom=False) ax7.set_xlabel("Altitude (km)") ax7.xaxis.set_label_position("top") ax7.yaxis.set_label_position("right") ax7.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma ionisation rate ax8 = fig.add_subplot(4,2,4) ax8.plot(alt, result.plasma_ionisation_rate, color="black") ax8.grid() ax8.set_ylabel("Ionization Rate\n(cm$^{-3} \cdot $s$^{-1}$)") ax8.set_xlim(80,250) ax8.set_ylim(bottom=0) ax8.yaxis.set_label_position("right") ax8.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma temperatures ax9 = fig.add_subplot(4,2,6) ax9.plot(alt, result.plasma_electron_temperature, label="Electron Plasma", color="blue") ax9.plot(alt, result.plasma_ion_temperature, label="Ion Plasma", color="red") ax9.grid() ax9.legend(fontsize=9) ax9.set_ylabel("Temperature\n(K)") ax9.set_xlim(80,800) ax9.set_ylim(bottom=0) ax9.yaxis.set_label_position("right") ax9.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma conductivities ax10 = fig.add_subplot(4,2,8) ax10.plot(alt, result.plasma_pederson_conductivity, label="Pederson Conductivity", color="green") ax10.plot(alt, result.plasma_hall_conductivity, label="Hall Conductivity", color="black") ax10.grid() ax10.legend(fontsize=9) ax10.set_ylabel("Conductivity\n(S/m)") ax10.set_xlim(80,250) ax10.set_ylim(bottom=0) ax10.set_xlabel("Altitude (km)") ax10.yaxis.set_label_position("right") ax10.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # render the plot plt.show() # --- # # ## **Inversion Calculations** # ### **Perform a basic 'inverse' calculation** # # Using ATM you can also perform inversion calculations to derive various outputs using emission intensities as inputs. # # This function works very similarly to the 'forward' function, where-by some inputs are required, some are optional, and outputs are enabled using True/False flags as part of the request. # # Please note that the limitations on latitude and longitude range are designed to constraint request to the targeted region that the TREx optical instrumentation are deployed to. We also note that the model only takes into account data when the optical instruments were operating at 105 degrees solar zenith angle, which is several degrees lower than nominal data acquisition. This ultimately means that the beginning and end of each night have been excluded when deriving the model algorithm. # # Full documentation on this function is [in the `inverse()` function documentation](https://docs.aurorax.space/code/pyaurorax_api_reference/pyaurorax/models/atm/index.html#pyaurorax.models.atm.ATMManager.inverse). # # # Input notes: # # - timestamp is limited to a set of years # - if you supply a request outside of this valid range, an exception will be raised # - 2019-2023 as of June 2024, more will be added # - latitude and longitude # - are to be in geodetic coordinates # - latitude is currently limited to ≥50.0 and <61.5 degrees # - longitude is currently limited ≥-110 and <-70 and degrees # - valid values for nrlmsis_model_version are '00' and '2.0' # - valid values for precipitation_flux_spectral_type are 'gaussian' and 'maxwellian' # - intensity parameters are expected to be in Rayleighs # # # # Output notes: # # - output parameter of the request are toggles the enable/disable each field's inclusion in the response # - all output parameters are false by default # - altitude is in kilometers # - energy flux: erg/cm2/s # - characteristic energy: eV # - emission data: 1-D array -- volume emission rate (1/cm^3/s) # - plasma electron density: 1-D array -- density (cm^-3) # - plasma O2+ density: 1-D array -- density (cm^-3) # - plasma NO+ density: 1-D array -- density (cm^-3) # - plasma O+ density: 1-D array -- density (cm^-3) # - plasma ionisation rate: 1-D array -- ionisation rate (1/cm^3/s) # - plasma electron temperature: 1-D array -- temperature (K) # - plasma ion temperature: 1-D array -- temperature (K) # - plasma peterson conductivity: 1-D array -- conductivity (S/m) # - plasma hall conductivity: 1-D array -- conductivity (S/m) # - neutral O2 density: 1-D array -- density (cm^-3) # - neutral O density: 1-D array -- density (cm^-3) # - neutral N2 density: 1-D array -- density (cm^-3) # - neutral N density: 1-D array -- density (cm^-3) # - neutral temperature: 1-D array -- temperature (K) # # Exactly like the 'forward' calculations, ATM inverse requests work in a way where you toggle ON whatever outputs you want back. This allows you to get back only what you want. This mechanism is controlled by the `ATMInverseOutputFlags()` class that must be instantiated before making the calculation. # # As part of this class, there are helper functions that toggle all ON or OFF. # In[ ]: # set up our request # # just like the forward function, outputs are toggled on/off using a flag object. timestamp = datetime.datetime(2021, 10, 12, 6, 0, 0) latitude = 58.227808 longitude = -103.680631 intensity_4278 = 2302.6 intensity_5577 = 11339.5 intensity_6300 = 528.3 intensity_8446 = 427.4 output = pyaurorax.models.ATMInverseOutputFlags() output.energy_flux = True output.characteristic_energy = True output.oxygen_correction_factor = True # In[ ]: # perform the calculation result = aurorax.models.atm.inverse(timestamp, latitude, longitude, intensity_4278, intensity_5577, intensity_6300, intensity_8446, output) # let's view the output values we asked for print("Energy Flux: %.03f erg/cm2/s" % (result.energy_flux)) print("Characteristic Energy: %.03f eV" % (result.characteristic_energy)) print("Oxygen Correction Factor: %.03f" % (result.oxygen_correction_factor)) # In[ ]: # let's view the result object like we did for the forward calculation result.pretty_print() # ### **Do a request with all output parameters** # # You can also do a request and specify the output flags to return everything that the ATM 'inverse' endpoint has to offer. Below, we're going to do that and plot all data. # # For this request, we're going to also change the precipitation flux spectral type to maxwellian, to illustrate that either 'gaussian' or 'maxwellian' can be used. # In[ ]: # set up parameters timestamp = datetime.datetime(2021, 10, 12, 6, 0, 0) latitude = 58.227808 longitude = -103.680631 intensity_4278 = 2302.6 intensity_5577 = 11339.5 intensity_6300 = 528.3 intensity_8446 = 427.4 # set output flags output = pyaurorax.models.ATMInverseOutputFlags() output.set_all_true() # perform calculation result = aurorax.models.atm.inverse(timestamp, latitude, longitude, intensity_4278, intensity_5577, intensity_6300, intensity_8446, output) # show result object result.pretty_print() # Let's plot everything we got back. # In[ ]: # print the energy flux, characteristic energy, and oxygen correction factor print("Energy Flux: %.03f erg/cm2/s" % (result.energy_flux)) print("Characteristic Energy: %.03f eV" % (result.characteristic_energy)) print("Oxygen Correction Factor: %.03f\n" % (result.oxygen_correction_factor)) # print all height-integrated Rayleighs data print("""Height-integrated Rayleighs: 427.8nm: %.02f R 557.7nm: %.02f R 630.0nm: %.02f R 844.6nm: %.02f R""" % (result.height_integrated_rayleighs_4278, result.height_integrated_rayleighs_5577, result.height_integrated_rayleighs_6300, result.height_integrated_rayleighs_8446)) # plot the emission, plasma, and neutral data # # we'll do this all in one plot, but made up from many subplots alt = result.altitudes fig = plt.figure(figsize=(8,8)) # plot all the emissions as a column of subplots # # blueline emission ax1 = fig.add_subplot(4,2,1) ax1.plot(alt, result.emission_4278, label=r"4278 $\AA$", color="dodgerblue") ax1.legend() ax1.set_xlim(80,500) ax1.set_ylim(bottom=0) ax1.grid(axis="x") ax1.tick_params(axis="x", bottom=True, top=True, labeltop=True, labelbottom=False) ax1.xaxis.set_label_position("top") ax1.set_xlabel("Altitude (km)") ax1.xaxis.set_label_position("top") # greenline emission ax2 = fig.add_subplot(4,2,3) ax2.plot(alt, result.emission_5577, label=r"5577 $\AA$", color="green") ax2.legend() ax2.set_xlim(80,500) ax2.set_ylim(bottom=0) ax2.grid(axis="x") ax2.set_ylabel("Volume Emission Rate\n(cm$^{-3} \cdot $s$^{-1}$)") ax2.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # redline emission ax3 = fig.add_subplot(4,2,5) ax3.plot(alt, result.emission_6300, label=r"6300 $\AA$", color="red") ax3.legend() ax3.set_xlim(80,500) ax3.set_ylim(bottom=0) ax3.grid(axis="x") ax3.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # near-infrared 8446 A emission ax4 = fig.add_subplot(4,2,7) ax4.plot(alt, result.emission_8446, label=r"8446 $\AA$", color="blueviolet") ax4.legend() ax4.set_xlim(80,500) ax4.set_ylim(bottom=0) ax4.grid(axis="x") ax4.tick_params(axis="x", bottom=True, top=True, labelbottom=False) # plot the plasma data as a second column of subplots # # plasma density ax5 = fig.add_subplot(4,2,2) ax5.plot(alt, result.plasma_electron_density, label="Electron", color="green") ax5.plot(alt, result.plasma_o2plus_density, label="O$^{2+}$", color="black") ax5.plot(alt, result.plasma_noplus_density, label="NO$^{+}$", color="blue") ax5.plot(alt, result.plasma_oplus_density, label="O$^{+}$", color="red") ax5.grid() ax5.set_ylabel("Plasma Density\n(cm$^{-3}$)") ax5.legend(fontsize=9) ax5.set_xlim(80,700) ax5.set_ylim(bottom=0) ax5.tick_params(axis="x", bottom=True, top=True, labeltop=True, labelbottom=False) ax5.set_xlabel("Altitude (km)") ax5.xaxis.set_label_position("top") ax5.yaxis.set_label_position("right") ax5.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma ionisation rate ax6 = fig.add_subplot(4,2,4) ax6.plot(alt, result.plasma_ionisation_rate, color="black") ax6.grid() ax6.set_ylabel("Ionization Rate\n(cm$^{-3} \cdot $s$^{-1}$)") ax6.set_xlim(80,250) ax6.set_ylim(bottom=0) ax6.yaxis.set_label_position("right") ax6.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma temperatures ax7 = fig.add_subplot(4,2,6) ax7.plot(alt, result.plasma_electron_temperature, label="Electron Plasma", color="blue") ax7.plot(alt, result.plasma_ion_temperature, label="Ion Plasma", color="red") ax7.grid() ax7.legend(fontsize=9) ax7.set_ylabel("Temperature\n(K)") ax7.set_xlim(80,800) ax7.set_ylim(bottom=0) ax7.yaxis.set_label_position("right") ax7.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # plasma conductivities ax8 = fig.add_subplot(4,2,8) ax8.plot(alt, result.plasma_pederson_conductivity, label="Pederson Conductivity", color="green") ax8.plot(alt, result.plasma_hall_conductivity, label="Hall Conductivity", color="black") ax8.grid() ax8.legend(fontsize=9) ax8.set_ylabel("Conductivity\n(S/m)") ax8.set_xlim(80,250) ax8.set_ylim(bottom=0) ax8.set_xlabel("Altitude (km)") ax8.yaxis.set_label_position("right") ax8.tick_params(axis="y", left=False, right=True, labelleft=False, labelright=True) # render the plot plt.show() # In[ ]: