Quantcast
Channel: Modeling global warming with a sinusoidal fit in Python - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 2

Modeling global warming with a sinusoidal fit in Python

$
0
0

I would like to model global warming from temperature records recorded daily from June 1920 to October 2019 in Montélimar on Python. To do this, I would first like to model these seasonal variations by a sinusoidal fit.

Here is the sinusoidal model that I have reproduced: $$T(t) = A \sin(\omega t + \phi) + B$$ where the parameters A (amplitude), 𝜙 (phase) and B (average temperature) are fitted to the data with $$\omega = \frac{2 \pi}{365}$$

However, such a model fitted to the whole data set does not give any increase in average temperature. I therefore try to apply a sinusoidal fit for each decade.

I first plotted the data in the data file like this:

# Import of modulesimport numpy as npimport matplotlib.pyplot as pltimport pandas as pdfrom scipy.optimize import curve_fit# Read the montelimar_temperature containing the dataDate, Temperature = np.loadtxt('montelimar_temperature.dat', unpack = True)Date = Date + 2400000.5 # Conversion of dates from Modified Julian Days to Julian Daysdate_new = pd.to_datetime(Date, unit = 'D', origin = "julian") # Convert Julian Days dates to datetime64 format# Size of the graphplt.figure(figsize = (25, 9))# Plot of the curveplt.plot(date_new, Temperature)# Title and othersplt.title("Evolution of daily recorded temperatures in Montélimar between 1920 and 2020", fontsize = 30) # Titleplt.xlabel("Year", fontsize = 20) # Title of the absissaplt.ylabel("Temperature (°C)", fontsize = 20) # Title of the ordinatesplt.grid()plt.show()

Then I created a time variable so I could do my decadal average. I applied the sine fit to all the decades in the data file, then plotted the entire graph with the fit. You will find my code below. It works flawlessly, but I feel like I'm repeating myself a lot with the code. I feel like I could do this without so much repetition, but every time I try I get errors and my graphs don't plot correctly. That's why I would like to know if there is a way to rewrite this in a cleaner way.

Here is the code I would like to simplify:

# Definition of the function for sinusoidal adjustmentdef sinLaw(t, A, phi, B):    omega = (2 * np.pi) / 365    return A * np.sin(omega * t + phi) + Bimport datetimecurrent_decade = np.datetime64(date_new[0], 'Y')time_for_B = np.linspace(1930, 2020, 10)#print(time_for_B)count_time = np.array([]) # Variable to store the temperatures of a decadecount_date = np.array([])B_list = np.array([])n = 1for i in range(0, len(date_new)): # Browse the date_new indexes to simply access the date_new value and the corresponding temperature    if np.datetime64(date_new[i], 'Y') >= current_decade + np.timedelta64(10, 'Y'): # Arrived at a new decade        current_decade = current_decade + np.timedelta64(10, 'Y') # Change in the current decade        n = n + 1        plt.figure(n)        plt.plot(count_date, count_time)        N = len(count_date)        time_model = np.linspace(0, N, N)        # Fit of the linear model        solution = curve_fit(sinLaw, time_model, count_time)        # Identification of the parameters        A, phi, B = solution[0]        # Display the result        #print('A = {:4.2f} amplitude'.format(A))        #print('B = {:4.2f} °C'.format(B))        #print('phi = {:4.2f} radians'.format(phi))        # Display the sine fit        y = sinLaw(time_model, A, phi, B)        B_list = np.append(B_list, B)        plt.plot(count_date, y)        errors = 5. * np.ones(y.shape)        # Fit of the linear model        solution, pcov = curve_fit(sinLaw, time_model, y, sigma = errors, absolute_sigma = True)        # Identification of the model parameters        A, phi, B = solution        # Calculation of the uncertainty on the fitted parameters        perr = np.sqrt(np.diag(pcov))        # Display        print('B = {:5.7f} ± {:5.3f} °C'.format(B, perr[0]))        count_time = np.array([])        count_date = np.array([])    count_time = np.append(count_time, Temperature[i])    count_date = np.append(count_date, date_new[i])n = n + 1plt.figure(n)plt.plot(count_date, count_time, '.')N = len(count_date)time_model = np.linspace(0, N, N)# Fit of the linear modelsolution = curve_fit(sinLaw, time_model, count_time)# Identification of the parametersA, phi, B = solution[0]# Display the result#print('A = {:4.2f} amplitude'.format(A))#print('B = {:4.2f} °C'.format(B))#print('phi = {:4.2} radians'.format(phi))# Display the sine fity = sinLaw(time_model, A, phi, B)B_list = np.append(B_list, B)plt.plot(count_date, y)#print('B =', B_list)plt.grid()plt.figure(n + 1)plt.plot(time_for_B, B_list)plt.grid()# Definition of the table of measurement errorserrors = 0.117 * np.ones(B_list.shape)solution, pcov = curve_fit(sinLaw, time_model, count_time)# Identification of the model parametersA, phi, B = solutionperr = np.sqrt(np.diag(pcov))# Displayprint('B = {:5.7f} ± {:5.3f} °C'.format(B, perr[0]))# Graphical representation of the data with the error barsplt.errorbar(time_for_B, B_list, yerr = errors, marker = '+', linestyle = '')# Graph optionplt.xlabel('Date [year]')plt.ylabel('B [°C]')plt.show()

Here is the result I get with this code and which corresponds to what I expect: output

I can't put all the data of my file here because it contains 36296 lines and I can't attach a file but you will find below a sample of the first 100 lines of my file which has the name "montelimar_temperature.dat":

2255322.6
2255422.6
2255524.8
2255617.5
2255716.5
2255818.3
2255918.1
2256016.8
2256117.0
2256217.5
2256318.0
2256417.8
2256517.7
2256617.6
2256716.9
2256818.0
2256918.4
2257017.4
2257119.8
2257221.0
2257322.5
2257420.6
2257519.6
2257621.7
2257722.6
2257821.7
2257921.4
2258021.6
2258119.6
2258220.2
2258318.0
2258422.4
2258522.7
2258619.4
2258713.6
2258816.8
2258916.0
2259015.2
2259115.0
2259214.1
2259317.7
2259415.7
2259516.4
2259614.4
2259719.8
2259817.2
2259919.4
2260015.3
2260114.3
2260218.6
2260318.8
2260420.0 
2260516.6
2260617.6
2260716.0
2260816.3
2260916.2
2261017.3
2261115.4
2261214.4
2261313.0
2261418.4
2261516.0
2261613.4
2261711.9
2261812.8
2261911.6
2262012.2
2262111.0
2262213.6
2262314.0
2262411.2
2262510.3
2262610.2 
226276.8
2262810.2
2262910.0
226308.2
226318.0
226328.8
226338.0
226349.8
226358.0
226365.6
226377.8
226387.2
226395.6
226405.9
226416.9 
226426.0
226436.6
226448.7
2264511.5
2264611.0
226478.9
226489.4
226498.9
226505.1
226511.5
226525.3

The columns have no names. The first column corresponds to dates in Modified Julian Days and the second column corresponds to temperatures in degrees Celsius.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images