 CoCalc Public FilesRelease / RisingTemperature.ipynb
Authors: Ingo Dahn, Ambjörn Naeve
Description: Learning Materials released by the MathTrek Team
Compute Environment: Ubuntu 20.04 (Default)

# Part I: Temperature

By Ingo Dahn, (Koblenz, Germany [email protected]) and Ambjörn Naeve (Stockholm, Sweden [email protected])

Weather balloons are a simple, but important mean to explore the atmosphere. They carry radiosondes high up in the air (how high?) These radiosondes measure several parameters of the atmosphere during their flight, for instance air temeperature and air pressure. Weather balloons collect many data. With a good understanding of athmospheric phenomena we should be able to predict these data to a certain extent. Can you do it?

This notebook lets you perform your own experiments with real weather balloons. We start with a simple method for calculating the air temperature in various height and check it against the measurements of a real weather balloon. And you can repeat this experiment yourself with many ballon risings! Can you come up with a better model?

This notebook is made of a sequence of cells:

• Text cells, explaining what we do. The text cells analyze a specific default balloon flight. They do not change and, depending on your working environment, you may not be able to change the content of text cells.

• Code cells with Sage code. You must _execute_ these cells to actually run the code. Depending on your environment, you execute cells by pressing the Execute button, by clicking into the cell and pressing Shift+Return or by selecting a Run item from the Cell menu. You can modify the content of code cells and you should do this in the places indicated in order to perform your own live experiments with real weather data! Note: Code cell calculations mostly use the results of calculations of previous cells. Therefore it is important that they are executed in the given order.

Hovering the mouse over the SageMath icon will reveal some additional explanations on the code - try it

• Interactive questions from Wamap. Many of these questions come with written examples, explaining the underlying Math.

Don't worry, if you don't understand the content of the code cells! We start simple and so you don't need to know a lot of Math, Physics or Programming - just go and experiment! Whenever you run into trouble - have a look at our .

## Launching the Balloons

Let's go to the weather station in Idar-Oberstein/Germany. It is located 105 km (ca 65 miles) southwest of Frankfur/Main at a height of 376 m.

Or fly high up with a weather balloon in this video from Overlook Horizon:

The German Weather Service (Deutscher Wetterdienst) provides data from it's radio sondes on the web. The following cell fetches these recent data from the Idar-Oberstein weather station for you to work with. "

If it has in line 2 randomBalloon=False (the default) it uses a specific sample balloon flight which is discussed in the comments. You may change it to randomBalloon=True in order to select data from a randomly selected balloon flight.

In the subsequent chapters we discuss some mathematical models of the atmosphere. In order to compare the predictions of these models with the data from the weather balloons, the following cell must be executed first.

In :
# Change the value of randomBalloon to True in order to select a flight by chance
randomBalloon=False
station=station()
if randomBalloon:
flight=station.getFlight('random')
else:
flight=station.getFlight()
temp=flight.dataPoints('height','temperature')
press=flight.dataPoints('height','pressure')

Ready to analyze 119 data points from one flight on 30.09.2020.

## Part I: Temperature

Temperature is one of the basic properties of any gas. Air temperature is easy to determine with a thermometer.

### Cool

There is a simple model describing the decrease of temperature when the balloon gets higher up. Usin this model requires some understanding of linear functions. Don't forget to answer the questions!

People climbing mountains early noted that the air gets colder as they climb up. Based on measurements with thermometers scientists carried uphill, scientist calculated that the air temperature $t(x)$ decreases by 6.5°C if height is increased by 1000 m (a so-called Lapse Rate) . $T(x+1000)=T(x)-6.5$ Using such a lapse rate and a given temperature on the ground we can use this to calculate the temperature at any height.

Try to answer such a question by yourself. If you find it difficult, look at the written example, that comes with the question. If you have problems entering a formula, have a look at the .

Let's assume a temperature of 15°C on the ground (we may change that later): $T(0)= t_0 =15$. What would be the temperature at a height of 7500 m according to this model? You can calculate that using the standard lapse rate $l_s=\frac{-6.5}{1000}=-0.0065$ of change in °/m. In :
t_0=15
l_s=-6.5/1000
T(x)=l_s*x+t_0
T(7500)

-33.7500000000000

The temperature at a height of 7500 m is, according to our model. -33.75°C.

Modify the cell above to calculate the temperature at 9200 m by replacing in line 4 7500 with 9200! Depending upon the context where you read this, you need to select Run from the Cell menu or press Shift+Return or click the Execute button to evaluate the cell for the new height.

Play around and calculate the expected air temperature at various heights; vary also the ground temperature t_0!

Let's plot this function - the temperature should decrease as we get higher up :

In :
plot(T,0,20000,axes_labels=["Height (m)","Temperature (°C)"],gridlines=True) It seems to get pretty cold up there. That diagram would be more intuitive if the Height axes goes upward (on the ordinates) and the Temperature values are written horizontally (on the abscissae). We can get that presentation when we interchange the role of height and temperature, i.e. we let the height depend upon the temperature (do you think that is weird?), i.e. we plot the inverse function $T_{inv}$ of our temperature function $T$.

Can you calculate the inverse of our function $T$?

If not, look at the video that comes with the following question.

Now let's plot $T_{inv}$. You can play with the lapse rate lrand the ground temperature t_0 using your mouse or arrow keys to explore effects of their change. In :
@interact
def _(lr=slider(4,8,step_size=0.1,default=6.5),t_0=slider(-30,30,step_size=1,default=15)):
c=-lr/1000
T1_inv(x)=(x-t_0)/c
show(plot(T1_inv,xmin=-100,xmax=30,ymin=0,ymax=15000,axes_labels=["Temperature (°C)","Height (m)"],gridlines=True))


That looks much more natural. Now we are ready for a reality test.

### Really Cool

Let's see, what the balloon actually measured up in the air!

Let us plot the temperature that our balloon has measured at the various heights. As in the previous plots, we draw the inverse function to direct the height axis upwards. In :
temp_inv=invert(temp)
balloonPlot=list_plot(temp_inv,axes_labels=['Temperature (°C)','Height (m)'],gridlines=True)
balloonPlot Oops, that doesn't look like what our model predicted.

We observe, that the development of air temperature with height on this day has three phases.

• Up to 4000 m the air temperature behaves somewhat irregularly
• in the range between 4000 m and 12000 m it decreases more or less linearly - the curve is almost a straight line, similar to our model
• it increases and oscillates again above 12000 m

Let's call the upper region of oscillating temeperature - here above 12000 m - Tropopause and the region below it Troposphere.

Clearly, our simple linear model does not work in the Tropopause, but perhaps it works in the upper region of the Troposphere? Let's check!

This region is between 4000 m and 12000 m for the default flight, it may be different for other flights! In :
# Adapt these two values if you are not using the default flight
linMin=4000
linMax=12000
print("Range of presumed linear temperature descent defined.")

Range of presumed linear temperature descent defined.

As we don't have the real temperature at height 0, we have to redefine our model function $T(x)$ by using the temperature at a another height $h_t$.

Instead of defining the linear function such that $T(0)=t_0$ we define $T$ such that $T(h_t)=t_h$ for some data point $(h_t,t_h)$ from our flight. We chose this data point as the first measurement in the height region we are interested in, i. e. the first data point at a height above 4000 m. In :
i=0
while temp[i] < linMin:
i+=1
h_t=temp[i]; t_h=temp[i]; i_h=i
print("The first data point above %i m is at a height of %i m with an air temperature of %f°C."%(linMin,h_t,t_h))

The first data point above 4000 m is at a height of 4119 m with an air temperature of -3.700000°C.

When we know that $T(h_t)=l_s\cdot h_t+t_0=t_h$, where $t_0$ is the unknown temperature at sea level, then $t_0=t_h-l_s\cdot h_t$ and we have our new model $T(x)=l_s x+t_0$. We need to define $T(x)$ such that $T(4119)=-3.7$. Let's calculate $t_0$ as described above.

Try a similar problem yourself!
We now calculate a new model function for the new balloon temperature data, as you did in the last question. In :
t_0 = t_h-l_s*h_t
T(x)=l_s*x+t_0
print("T(x)=",T(x))
show(LatexExpr("t_0 = "),t_0)
show(LatexExpr("T(x)="),T(x))

T(x)= -0.00650000000000000*x + 23.0735000000000
$t_0 = 23.0735000000000$
$T(x)= -0.00650000000000000 \, x + 23.0735000000000$

A side remark on accuracy in case you wonder why there are so many zeros:

Our computer calculates with a limited precision and the number of trailing zeros indicates the precision that is actually used. Real data, as those from the weather balloons, have a much lower accuracy and so many of the trailing decimals cannot be taken seriously. Nevertheless we use the calculated data with all their digits in order to avoid accumulating rounding errors and to keep the code simple.

Let's now compare the data from our model with the data from our balloon - recall that we have to compare the balloon data with the inverse function $T_{inv}$. We combine the previous plot of the balloon data with the plot of our model function inverse. In :
T_inv(x)=(x-t_0)/l_s
show(balloonPlot+plot(T_inv,-70,20,color='red'),gridlines=True) That's not a very good match! The simple linear model predicts a more strong decrease of temperature than shown by the measurement. Well, that may be due to particular conditions at this day at this place and we need to analyse more balloon reports. At least, the adequate laps rate may vary from day to day - but by how much?

### Improving the Model

In order to get an indication for a better model, we may try to find a linear function that provides the best fit to the data between 4000 m and 12000 m.

This can be achieved by a mathematical method called Linear Regression. We can use Linear Regression to find a better model and plot it against the balloon data. In :
dataLin0=[p for p in temp_inv if p > linMin]
dataLin=[p for p in dataLin0 if p< linMax]
var('a,b,x')
f_lin(x)=a*x+b
q=find_fit(dataLin, f_lin, solution_dict = True)
aLin=q[a];bLin=q[b]
show(f_lin(a=aLin,b=bLin))
show(balloonPlot+plot(f_lin(a=aLin,b=bLin),-70,20,color='red',gridlines=True))
print(f_lin(a=aLin,b=bLin))

$-126.25666221248792 \, x + 3721.6288391232924$ -126.25666221248792*x + 3721.6288391232924

That fits much better than the original model. To get the real temperature lapse rate in the upper troposphere, we have to convert the fitting function by taking its inverse. In :
show((1/aLin)*x-(bLin/aLin))
lapse=round((-1000/aLin),1)
print((1/aLin)*x-(bLin/aLin))
print("The temperature decreases in the upper part of the troposphere by about",str(lapse)+"° each 1000 m.")

$-0.007920374121066309 \, x + 29.47669274560618$
-0.007920374121066309*x + 29.47669274560618 The temperature decreases in the upper part of the troposphere by about 7.9° each 1000 m.

We see, that in fact the air temperature decreases by 7.9°C every 1000 m!

### Temperature Summary

We have started with the hypothesis that the air temperature decreases by 6.5°C when the height increases by 1000 m. This has led us to establish a linear model for the development of air temperature.

Looking at the data from one radio balloon flight suggests that the development of air temperature follows different laws in the lower and in the upper part of the atmosphere travelled by the balloon, providing indications for at least three layers of the atmosphere. In the upper and in the lower layer, not even the linear form of our model is adequate, while in the middle layer a linear model fits well, but we have to adjust the cofficients of our model to make it fit to the data.

Criticism: Climate data can depend upon many factors, e.g. geographic location and season of the year. In order to evaluate our claims, they need to be checked against many weather balloon data. Only then may we have a chance to understand the various factors influencing and changing our climate.

ToDo: Look for answers to the following questions.

• Can these claims be confirmed by other balloon flights? You can try this by modifying the first code cell above to load the data from a random balloon flight from the Idar-Oberstein weather station.
• How do the coefficients of the model vary between different flights? What might be values for the coefficients of the linear model that provide an optimal fit for all flights?
• How does the season of the year and the time of day, with their different intensity of sun light, influence the development of the air temperature? This notebook has all the data required, but answering the question will require some programming.
• How may other properties of the athmosphere depend upon each other? For instance, how does pressure depend upon height? How does temperature depend on pressure? (Note: Data points for pressure can be obtained at flight.dataPoints('height','pressure'). This requires some adaptation of the code in this notebook.
• Which model may describe the oscillation of temperature in the Tropopause? How can these be explained?

The following cell prints some basic status data from this notebook for re-use in other notebooks. Execute it and copy it's output into the input cell of another notebook, designated by a green border, or save it for later use in a text file.

In :
print('temp =',temp)
print('press =',press)

temp = [(376, 15.0), (500, 13.9), (767, 11.4), (996, 9.9), (1000, 9.9), (1373, 7.4), (1469, 6.8), (1500, 6.6), (1785, 5.2), (1795, 5.2), (1845, 4.2), (1885, 3.4), (1936, 5.0), (1966, 5.4), (1976, 5.6), (2000, 5.8), (2007, 5.8), (2048, 6.5), (2111, 7.6), (2280, 6.0), (2647, 2.8), (2960, 0.1), (3052, -0.7), (3077, -0.9), (3250, -1.1), (3356, -1.9), (3546, -3.3), (3643, -2.3), (3816, -3.5), (3991, -3.5), (4119, -3.7), (4275, -5.2), (4634, -8.7), (4895, -9.9), (4937, -10.1), (5366, -12.5), (5395, -12.8), (5513, -13.9), (5680, -15.3), (5815, -16.1), (6563, -22.2), (6798, -24.1), (6832, -24.3), (7320, -27.5), (7558, -28.9), (8448, -36.9), (8694, -39.1), (8757, -39.7), (9055, -42.1), (9077, -42.3), (9320, -44.3), (9729, -47.7), (10063, -50.7), (10136, -51.1), (10510, -54.5), (10617, -55.7), (11319, -61.1), (11347, -61.3), (11461, -61.9), (11910, -63.7), (11999, -64.3), (12093, -63.4), (12489, -59.6), (12523, -59.3), (12880, -58.4), (13220, -57.5), (13418, -58.6), (13620, -59.7), (13700, -58.7), (13786, -58.6), (13872, -58.4), (14702, -57.0), (15164, -56.3), (15326, -56.0), (15549, -55.7), (16081, -56.7), (16270, -57.1), (16609, -57.0), (16847, -57.0), (17037, -57.0), (17247, -56.9), (17435, -56.9), (17675, -56.8), (18237, -56.7), (18530, -56.7), (18599, -56.4), (18833, -55.5), (18978, -55.6), (19197, -55.8), (19878, -56.3), (20223, -56.6), (20660, -56.9), (20767, -57.0), (20870, -57.2), (21358, -57.8), (21886, -58.5), (23890, -57.1), (24557, -56.9), (25070, -56.7), (25628, -56.5), (26241, -56.4), (26460, -56.3), (26923, -56.4), (27456, -56.5), (27682, -56.5), (27721, -56.5), (28121, -55.2), (28419, -54.3), (28732, -53.3), (29063, -52.4), (29413, -51.3), (29730, -50.4), (29952, -49.8), (30300, -48.8), (30733, -47.6), (30930, -47.1), (30997, -46.9), (32406, -47.7), (34448, -40.7)] press = [(376, 969.0), (500, 954.9), (767, 925.0), (996, 900.0), (1000, 899.6), (1373, 860.0), (1469, 850.0), (1500, 846.9), (1785, 818.0), (1795, 817.0), (1845, 812.0), (1885, 808.0), (1936, 803.0), (1966, 800.0), (1976, 799.0), (2000, 796.7), (2007, 796.0), (2048, 792.0), (2111, 786.0), (2280, 770.0), (2647, 736.0), (2960, 708.0), (3052, 700.0), (3077, 698.0), (3250, 683.0), (3356, 674.0), (3546, 658.0), (3643, 650.0), (3816, 636.0), (3991, 622.0), (4119, 612.0), (4275, 600.0), (4634, 573.0), (4895, 554.0), (4937, 551.0), (5366, 521.0), (5395, 519.0), (5513, 511.0), (5680, 500.0), (5815, 491.0), (6563, 444.0), (6798, 430.0), (6832, 428.0), (7320, 400.0), (7558, 387.0), (8448, 341.0), (8694, 329.0), (8757, 326.0), (9055, 312.0), (9077, 311.0), (9320, 300.0), (9729, 282.0), (10063, 268.0), (10136, 265.0), (10510, 250.0), (10617, 246.0), (11319, 220.0), (11347, 219.0), (11461, 215.0), (11910, 200.0), (11999, 197.0), (12093, 194.0), (12489, 182.0), (12523, 181.0), (12880, 171.0), (13220, 162.0), (13418, 157.0), (13620, 152.0), (13700, 150.0), (13786, 148.0), (13872, 146.0), (14702, 128.0), (15164, 119.0), (15326, 116.0), (15549, 112.0), (16081, 103.0), (16270, 100.0), (16609, 94.8), (16847, 91.3), (17037, 88.6), (17247, 85.7), (17435, 83.2), (17675, 80.1), (18237, 73.3), (18530, 70.0), (18599, 69.2), (18833, 66.7), (18978, 65.2), (19197, 63.0), (19878, 56.6), (20223, 53.6), (20660, 50.0), (20767, 49.2), (20870, 48.4), (21358, 44.8), (21886, 41.2), (23890, 30.0), (24557, 27.0), (25070, 24.9), (25628, 22.8), (26241, 20.7), (26460, 20.0), (26923, 18.6), (27456, 17.1), (27682, 16.5), (27721, 16.4), (28121, 15.4), (28419, 14.7), (28732, 14.0), (29063, 13.3), (29413, 12.6), (29730, 12.0), (29952, 11.6), (30300, 11.0), (30733, 10.3), (30930, 10.0), (30997, 9.9), (32406, 8.0), (34448, 5.9)]

You may use the following cell for your own experiments.

In [ ]: