72 csv_hydrogen_key=
"Hden(cm-3)",
73 csv_height_key=
"Heit(km)",
75 transparent_background: bool =
False,
79 Path to MSISE CSV file containing hydrogen profile.
82 Delimiter used in CSV file. Default is ";".
85 Key for hydrogen profile used in CSV file. Default is "Hden(cm-3)".
88 Key for height in km used in CSV file. Default is "Heit(km)".
91 If the exponential fit shall be plotted and saved, pass over a path here. Default is "" meaning no plotting.
93 transparent_background:
94 Transparent background for plot if True. Does nothing if plot_path is "". Default is False.
96 This function can be used to create an ozone initial state,
97 which depends on an exponential fit of the hydrogen density
98 instead of the actual hydrogen profile.
100 This is due to the hydrogen tending to 0 shortly after
101 the OH peak altitude of ca. 83km. Ozone would thus tend to infinity
102 for these lower altitudes. However, its actual minimum should be lower
103 than where the hydrogen density reaches 0 (ca. 75km-80km).
105 Therefore, the hydrogen density is fit to an exponential curve allowing
106 the ozone to decay for altitudes less than 80km. This additional ozone
107 is not in steady state and thus needs further correction in the source term.
112 from scipy.optimize
import curve_fit
118 dataframe = pd.read_csv(csv_file_path, delimiter=csv_separator)
120 dataframe = dataframe[[csv_height_key, csv_hydrogen_key]]
122 dataframe[
"Heit(m)"] = dataframe[csv_height_key].mul(1e3)
124 dataframe = dataframe.sort_values(by=
"Heit(m)", ascending=
False)
129 hydrogen = dataframe[csv_hydrogen_key].to_numpy()
130 derivative_of_hydrogen = np.diff(hydrogen)
133 sign_switch_index = 0
134 for i
in range(0, derivative_of_hydrogen.size):
136 if derivative_of_hydrogen[i] < 0
and np.all(derivative_of_hydrogen[i:] <= 0):
137 sign_switch_index = i
142 "Expected decrease in hydrogen in lower atmosphere. Exponential fit for ozone not possible"
149 hydrogen_values_to_fit = hydrogen[sign_switch_index::-1]
150 height_values_to_fit = dataframe[
"Heit(m)"].to_numpy()[sign_switch_index::-1]
151 hydrogen_log = np.log(hydrogen_values_to_fit)
154 def exp_func(x, a, b, c):
155 return a * np.exp(b * x) + c
157 def lin_func(x, a, b):
161 (a, b), _ = curve_fit(lin_func, height_values_to_fit, hydrogen_log)
164 (a, b, c), _ = curve_fit(
166 height_values_to_fit,
167 hydrogen_values_to_fit,
168 p0=[a, b, np.max(hydrogen_values_to_fit)],
172 print(
"a:", a,
", b:", b,
", c:", c)
173 import matplotlib.pyplot
as plt
174 from os.path
import splitext
177 hydrogen_fit = exp_func(dataframe[
"Heit(m)"], a, b, c)
179 plt.plot(hydrogen, dataframe[
"Heit(m)"], label=
"MSISE")
181 hydrogen_fit, dataframe[
"Heit(m)"], color=
"red", label=
"Exponential Fit"
188 plt.ylabel(
"Height (km)")
189 plt.xlabel(
r"[H] (cm$^{-3}$)")
190 plt.title(
"Exponential Fit for Hydrogen Profile")
191 plt.ylim(bottom=0, top=dataframe[
"Heit(m)"].max())
192 plt.legend(loc=
"upper left")
193 current_yticks = plt.yticks()
195 ticks=current_yticks[0], labels=((current_yticks[0] / 1e3).astype(np.int64))
198 plt.savefig(plot_path, transparent=transparent_background)
203 hydrogen_fit = exp_func(height_values_to_fit, a, b, c)
205 plt.plot(hydrogen_values_to_fit, height_values_to_fit, label=
"MSISE")
207 hydrogen_fit, height_values_to_fit, color=
"red", label=
"Exponential Fit"
212 plt.ylim(height_values_to_fit[0], height_values_to_fit[-1])
215 plt.ylabel(
"Height (km)")
216 plt.xlabel(
r"[H] (cm$^{-3}$)")
218 height_min_km = height_values_to_fit[0] / 1e3
219 height_max_km = height_values_to_fit[-1] / 1e3
222 height_min_km
if not height_min_km.is_integer()
else int(height_min_km)
225 height_max_km
if not height_max_km.is_integer()
else int(height_max_km)
229 f
"Exponential Fit for Hydrogen Profile from {height_min_km}km to {height_max_km}km"
232 current_yticks = plt.yticks()
234 ticks=current_yticks[0], labels=((current_yticks[0] / 1e3).astype(np.int64))
238 "_subsection".join(splitext(plot_path)), transparent=transparent_background
245 auto hydrogenFit = [](const double altitude) {
248 +
""" * tarch::la::pow(tarch::la::E, """
250 +
""" * altitude) + """
254 const double hydrogenPrime = hydrogenFit(x(1));
255 double lossOfO3 = 0.0;
256 for (int vibrationalState = 0; vibrationalState < 10; ++vibrationalState) {
257 lossOfO3 += ProductionRates::k5(T, vibrationalState) * hydrogenPrime;
260 // k6 production of ozone
261 const double productionOfO3 = (ProductionRates::k6(T) * M * O * O2);
262 Q[Shortcuts::O3] = productionOfO3 / lossOfO3;
264 const {{COMPUTE_PRECISION}} O3 = Q[Shortcuts::O3];"""
get_steady_state_for_ozone_MSISE(str csv_file_path, csv_separator=";", csv_hydrogen_key="Hden(cm-3)", csv_height_key="Heit(km)", str plot_path="", bool transparent_background=False)
csv_file_path: Path to MSISE CSV file containing hydrogen profile.