# Project on "powerproduction" dataset
### Loading the file
First import python packages. Next read in the csv which is saved in the same sub directory as the Jupyter Notebok file allowing the file path to be straight forward. Create the dfpower dataframe from the csv.

```python
# Import packages required for computation and visualisation. Also matplotlib magic command
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

dfpower = pd.read_csv('powerproduction.csv')
```

#### Checking the data
Check the file loaded ok using df.head( ) to view the first 5 (default) rows and df.tail( ) to view the last 5 rows. The amount of rows shown can be shown by inserting a number inside the brackets.

```python
dfpower.head()
```

      speed
      power

      0
      0.000
      0.0

      1
      0.125
      0.0

      2
      0.150
      0.0

      3
      0.225
      0.0

      4
      0.275
      0.0

```python
dfpower.tail()
```

      speed
      power

      495
      24.775
      0.0

      496
      24.850
      0.0

      497
      24.875
      0.0

      498
      24.950
      0.0

      499
      25.000
      0.0

#### Check for non zero 'power' values
The head and tail functions both returned 0.0 "power" values. We can use the command df.iloc[ ] to view row index values in the middle of the dataset to ensure power has some non zero values.

```python
dfpower.iloc[200:205]
```

      speed
      power

      200
      10.185
      22.305

      201
      10.210
      20.704

      202
      10.235
      30.341

      203
      10.260
      24.293

      204
      10.285
      20.636

#### Summary of the dataset
df.describe( ) is a very useful function to display important summary statistics about the dataset.

```python
dfpower.describe()
```

      speed
      power

      count
      500.000000
      500.000000

      mean
      12.590398
      48.014584

      std
      7.224991
      41.614572

      min
      0.000000
      0.000000

      25%
      6.324750
      5.288000

      50%
      12.550500
      41.645500

      75%
      18.775250
      93.537000

      max
      25.000000
      113.556000

### Data Visualisation
Creating a plot of the data is a good place to start when analysing to recognise if any trends or obvious relationships exist between variables. Here a scatterplot is most effective.

```python
plt.figure(figsize=(12,8))
sns.scatterplot(data=dfpower, x='speed', y='power')
plt.xlabel('speed (m/s)')
plt.ylabel('power output (kW)')
plt.title("Wind speed vs Power output")
plt.show();
```

### Linear Regression
Linear regression is the method of fitting a linear equation to the relationship between two variables in observed data. One variable is considered to be an explanatory variable otherwise known as an independent variable, and the other is considered to be a dependent variable. Simple linear regression is the case where only one explanatory variable exists i.e. one independent variable and one dependent variable. A common example is relating height and weight of individuals. A linear regression line can be written mathematically as the equation $y = mx + c$, where $x$ is the independent variable and $y$ is the dependent variable. The slope of the line is $m$, which is how much $y$ increases by when $x$ is increased by 1.0. $c$ is the intercept (the value of $y$ when $x = 0$). [1]

#### Fitting a line to  "powerproduction" dataset
From the scatter plot above it is apparent that a line of best fit would be reasonable suitable for at least the middle third of the plot however the left and right thirds of the plot appear to be more curved.

### Use Numpy to calculate the coefficients of the line (m and c)
First convert the dataframe columns to numpy arrays using the pandas .to_numpy() function.

```python
# Pandas function .to_numpy to create numpy array for each column
speed = dfpower['speed'].to_numpy()
power = dfpower['power'].to_numpy()
print(type(speed))
print(type(power))
```

    <class 'numpy.ndarray'>
    <class 'numpy.ndarray'>

#### Coefficients "m" & "c"

```python
# use numpy.polyfit to get the coefficients of the line of best fit
m = np.polyfit(speed, power, 1)[0]
c = np.polyfit(speed, power, 1)[1]
print(f'm(slope): {m:.3f}    c(intercept): {c:.3f}')
```

    m(slope): 4.918    c(intercept): -13.900

#### Plotting best fit line
Plot the best fit line on top of the original data

```python
# Plot the best fit line.
plt.figure(figsize=(12,8))
plt.plot(speed, power, '.b', label='Original data')
plt.plot(speed, m * speed + c, 'r-', label='Fitted line')

# Add axis labels and a legend.
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Plot of Numpy best fit line")
plt.legend()

# Show the plot.
plt.show();
```

#### Calculating Pearson's r value and R-squared value using Numpy
**Pearson's correlation coefficient (r)** is a statistic that measures linear correlation between two variables. Denoted a value between -1 and +1, A value of +1 is a total positive linear correlation; 0 being no linear correlation; and -1 being a total negative correlation.[2]
**R-squared** is the proportion of the variance in the dependent variable that is predictable from the independent variable.[3]

```python
# calculate both pearson's "r" and R-squared using Numpy
print(f'Pearson\'s correlation coefficient (r): {np.corrcoef(speed, power)[0,1]:5.2f}')
print(f'R-squared value: {np.corrcoef(speed, power)[0,1]**2:27.2f}')
```

    Pearson's correlation coefficient (r):  0.85
    R-squared value:                        0.73

### Use Scikit-Learn to perform the same Linear Regression [4]
From the official Scikit-Learn website [sklearn.linear_model.LinearRegression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html) "LinearRegression fits a linear model with coefficients w = (w1, …, wp) to minimize the residual sum of squares between the observed targets in the dataset, and the targets predicted by the linear approximation." It does essentially the exact same thing just slightly different. Coefficients are calculated by minimizing the least square error method. LSE is the most common cost function for fitting linear models. It is calculated as the sum of squared differences between the predicted (best fit line) and the actual values. Both Numpy.polyfit and sklearn use [linalg.lstsq](https://numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html) to solve for the coefficients.[5]
#### Define the Variables
First the X and y variables are defined.

```python
# create the variables. X must be a 2d array and y must be a 1d array
X = speed.reshape(-1,1)
y = power
```

#### Split the Data
The data is split into "Train" and "Test" sets with Scikit Learn train_test_split(). For this exercise the train set will be 80% of the data and the test set will be 20%. This is done by passing the ```test_size=0.20``` argument into the function

```python
# split the data into training and test sets using sklear test_train_split function
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=100)
```

#### Train the Algorithm
Using the split data the algorithm can now be trained. The Scikit-Learn package makes it very straight forward to implement linear regression models, as seen below there isn't much code involved. The ```fit()``` function is called from ```LinearRegression()```.

```python
# import LinearRegression class from sklearn
from sklearn.linear_model import LinearRegression
reg = LinearRegression()

# call the fit function
reg.fit(X_train, y_train)
```

    LinearRegression()

#### Coefficients for "m" & "c"

```python
print(f'm(slope): {reg.coef_[0]:.3f}    c(intercept): {reg.intercept_:.3f}')
```

    m(slope): 4.855    c(intercept): -13.281

#### R-Squared and Pearson's correlation coefficient
As before the R-squared value estimates how much of the changes in the $y$ value is due to the changes in the $x$ value compared to all of the other factors affecting the $y$ value. [Simple Linear Regression Notebook](https://github.com/ianmcloughlin/jupyter-teaching-notebooks/blob/master/simple-linear-regression.ipynb). This value is returned by the ```score(X, y)``` function.
Pearson correlation coefficient is the square root of R-squared.

```python
# Pearson's r is the sqrt of R-Squared which sklearn returns as score()
r_square = reg.score(X,y)
# Align the values using formatting (spacing)
print(f'Pearson\'s correlation coefficient (r): {np.sqrt(r_square):.2f}')
print(f'R-squared value: {r_square:26.2f}')
```

    Pearson's correlation coefficient (r): 0.85
    R-squared value:                       0.73

#### Predicting "y" values
Now that the algorithm has been trained and the coefficients etc. are calculated, $y$ values can be predicted. To do this, the test data will be used to see how accurately our algorithm predicts values for power output when given the wind speed.

```python
# use predict() function with X_test set
y_pred = reg.predict(X_test)
```

#### Comparing the Data
In order to compare the predicted vs the actual data a new dataframe can be created.

```python
# Create a new data frame of actual vs predicted values to compare
dfcomp = pd.DataFrame({'Speed': X_test.flatten(), 'PowerActual': y_test, 'PowerPredicted': y_pred})
```

The model is not really that precise as can be seen from the above dataframe. However a straight line is not the best fit for this dataset so these limitations are apparent.

#### Plotting best fit line
Plot the best fit line on top of the original data, include the Numpy.polyfit best line also for comparison.

```python
# Plot the original data vs sklearn best fit line.
plt.figure(figsize=(12,8))
plt.plot(speed, power, '.b', label='Original data')
plt.plot(X_test, y_pred, 'r-', label='Fitted line')
# Numpy best line
plt.plot(speed, m * speed + c, 'y-', label='Fitted line NP')

# Add axis labels and a legend.
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Plot of original data with Numpy & Sklearn lines of best fit")
plt.legend()

# Show the plot.
plt.show();
```

#### Evaluate the Accuracy of the Algorithm
The MAE, MSE & RMSE are used to evaluate the prediction error rates and model performance in regression analysis.
**MAE - Mean Absolute Error** - Measures the average difference between the original and predicted values over the data set

**MSE - Mean Squared Error** - Measures the average squared difference between the estimated values and the actual value.

**RMSE - Root Mean Squared Error** - Is the square root of the average of squared errors.

The formula for each is given below.

```python
# print the 3 common evaluation metrics. MAE, MSE, RMSE
from sklearn import metrics
# Align the numbers using formatting
print(f'Mean Absolute Error: {metrics.mean_absolute_error(y_test, y_pred): 12.4f}')
print(f'Mean Squared Error: {metrics.mean_squared_error(y_test, y_pred): 14.4f}')
print(f'Root Mean Squared Error: {np.sqrt(metrics.mean_squared_error(y_test, y_pred)): .4f}')
```

    Mean Absolute Error:      13.5093
    Mean Squared Error:       322.8440
    Root Mean Squared Error:  17.9679

### Polynomial Regression
Polynomial regression is a form of regression analysis in which the relationship between the independent variable $x$ and the dependent variable $y$ is modelled as an $n$th degree polynomial in $x$. [7]
#### Plotting Curves
Seaborn can plot a squared and cubed line of best fit for comparison

```python
# Create a 2x1 subplot to compare the squared and cubed order curves
#fig, (ax1, ax2, ax3, ax4) = plt.subplots(2, 2, figsize=(16,8))

plt.figure(figsize=(14,12))

# Seaborn regplot adds the regression order is the power number
plt.subplot(2,2,1)
sns.regplot(data=dfpower, x='speed', y='power', order=2, ci=None, line_kws={"color": "red"})
plt.title("Regression to 2nd order")

plt.subplot(2,2,2)
sns.regplot(data=dfpower, x='speed', y='power', order=3, ci=None, line_kws={"color": "red"})
plt.title("Regression to 3rd order")

plt.subplot(2,2,3)
sns.regplot(data=dfpower, x='speed', y='power', order=4, ci=None, line_kws={"color": "red"})
plt.title("Regression to 4th order")

plt.subplot(2,2,4)
sns.regplot(data=dfpower, x='speed', y='power', order=5, ci=None, line_kws={"color": "red"})
plt.title("Regression to 5th order")

plt.show();
```

### Numpy Polyfit
Numpy polyfit() can be used to calculate the coefficients of the the curve to the nth degree using least squares method

```python
# Use numpy polyfit to calculate the coefficients of the 2nd order curve
z2 = np.polyfit(speed, power, 2)

# A one-dimensional polynomial class built into Numpy calculates polynomials easily
# https://numpy.org/doc/stable/reference/generated/numpy.poly1d.html
p2 = np.poly1d(z2)
p2 # coefficients
```

    poly1d([ -0.07021949,   6.67418543, -21.22684391])

#### Plotting the new best fit line
Using the newly calculated coefficients of the form $ax^2 + bx + c$ to plot the 2nd order polynomial regression

```python
# Plot the original data vs newly fit polynomial line for x^n where n=2
plt.figure(figsize=(8,6))
plt.plot(speed, power, '.b',linewidth=3, label='Original data')
plt.plot(speed, p2(speed), 'r-', label='Fitted line x$^n$, n=2')

# Add axis labels and a legend.
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Regression to 2nd order")
plt.legend()

# Show the plot.
plt.show();
```

#### Calculate for 3rd, 4th, 5th order Polynomials

```python
# Use numpy polyfit to calculate the coefficients of the 3rd order curve
z3 = np.polyfit(speed, power, 3)

# A one-dimensional polynomial class built into Numpy calculates polynomials easily
# https://numpy.org/doc/stable/reference/generated/numpy.poly1d.html
p3 = np.poly1d(z3)
p3 # coefficients
```

    poly1d([ -0.05241927,   1.89485751, -12.94285866,  19.20130246])

```python
# Use numpy polyfit to calculate the coefficients of the 4th order curve
z4 = np.polyfit(speed, power, 4)

# A one-dimensional polynomial class built into Numpy calculates polynomials easily
# https://numpy.org/doc/stable/reference/generated/numpy.poly1d.html
p4 = np.poly1d(z4)
p4 # coefficients
```

    poly1d([-2.91850218e-03,  9.31965285e-02, -4.33771545e-01, -1.66731072e-01,
            3.89358544e+00])

```python
# Use numpy polyfit to calculate the coefficients of the 5th order curve
z5 = np.polyfit(speed, power, 5)

# A one-dimensional polynomial class built into Numpy calculates polynomials easily
# https://numpy.org/doc/stable/reference/generated/numpy.poly1d.html
p5 = np.poly1d(z3)
p5 # coefficients
```

    poly1d([ -0.05241927,   1.89485751, -12.94285866,  19.20130246])

#### Plot all of the results in a 2 x 2 grid

```python
plt.figure(figsize=(14,12))

# Seaborn regplot adds the regression order is the power number
plt.subplot(2,2,1)
plt.plot(speed, power, '.b',linewidth=3, label='Original data')
plt.plot(speed, p2(speed), 'r-', label='Fitted line x$^n$, n=2')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Regression to 2nd order")
plt.legend()

plt.subplot(2,2,2)
plt.plot(speed, power, '.b', label='Original data')
plt.plot(speed, p3(speed), 'r-',linewidth=3, label='Fitted line x$^n$, n=3')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Regression to 3rd order")
plt.legend()

plt.subplot(2,2,3)
plt.plot(speed, power, '.b', label='Original data')
plt.plot(speed, p4(speed), 'r-',linewidth=3, label='Fitted line x$^n$, n=4')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Regression to 4th order")
plt.legend()

plt.subplot(2,2,4)
plt.plot(speed, power, '.b', label='Original data')
plt.plot(speed, p5(speed), 'r-',linewidth=3, label='Fitted line x$^n$, n=5')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title("Regression to 5th order")
plt.legend()

# Show the plot.
plt.show();
```

Although the fourth order regression does follow the data quite closely the curve starts to return to zero after the 20 m/s mark, likewise the third and fifth order regression curves. After further research on the subject [this](https://github.com/killfoley/fundamentalsofDA_project/blob/main/Comparison%20of%20logistic%20functions%20for%20modeling%20wind%20turbine%20power%20curves.pdf) paper details how a logistic curve is best suited to model the power curve of a wind turbine.

### Logistic Regression
According to Villanueva & Feijóo, 2018 [8] In recent years logistic functions have been used to model wind turbine power curves. One of the functions a 3-parameter logistic function appears to be a suitable equation to model the power curve of a wind turbine due to it only having 3 parameters and producing an acceptable error level compared to 4-6 parameter logistic equations.

\begin{equation}
P(v)=\frac{\alpha}{1+e(-𝛽.(v-v_0))}
\end{equation}
where $P$ is the power output, $v$ is the wind speed, $\alpha$ is the curve’s maximum value, $v_0$ is the value of the midpoint and $\beta$ is the slope of the curve.

Mbamalu et al. introduced the following equation in their paper [9] showing it to be a typical symmetrical "S" curve with horizontal asymptotes at both $A$ and $C$, and proposing it as a hypothetical mathematical model for wind turbine power curves.

\begin{equation}
P(v)=\frac{A.v}{\sqrt{B-v^2}}+C
\end{equation}

#### scipy.optimize.curve_fit
Scipy.optimize.curve_fit uses non-linear least squares to fit a function to data. [10]

```python
# Import curve_fit function from scipy
from scipy.optimize import curve_fit

# Create the x and y variables
xdata = np.array(speed)
ydata = power

# Create the logistic function
def curvefunc(x, x0, A, B):
    y = A / (1 + (np.exp(-B*(x-x0))))
    return y

# Create the initial estimation
p0 = (np.amin(ydata), np.amax(ydata), np.amin(xdata))

# use the curve_fit function
popt, pcov = curve_fit(curvefunc, xdata, ydata, p0, method="lm")
popt
```

    array([12.23835574, 91.29727609,  0.62609684])

#### Plotting the calculated logistic curve

```python
plt.figure(figsize=(12,8))
plt.plot(xdata, ydata, 'o', label='original data')
plt.plot(xdata, curvefunc(xdata, *popt), linewidth=3, label='line of best fit')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title('plot of 3 Parameter Logistic Equation (3PLE) vs original data')
plt.legend()
plt.show();
```

This is a much better fit than the simple linear regression line originally calculated and it also appears to have a more suitable shape compared to any of the $n$th order polynomial displayed previously. The upper section of the curve does appear to level off a bit short of the cluster of data points but this may be due to the presence of zero $y$ values in that region or perhaps errors in the 3PLE calculation. A logistic equation with more parameters may yield a more accurate curve.

#### Model Mbamalu et al. function
Now try to model the equation proposed by Mbamalu et al. to see if it is similar.

\begin{equation}
P(v)=\frac{A.v}{\sqrt{B-v^2}}+C
\end{equation}

```python
from scipy import optimize

x_data = np.array(speed)
y_data = power

# Create the logistic function
def mbamfunc(x, A, B, C):
    y = A*x / (np.sqrt(B-x**2)) + C
    return y

# Create the initial estimation
p0 = (5, max(y_data), np.amin(x_data))

popt, pcov = curve_fit(mbamfunc, xdata, ydata, p0, method="lm")
popt
```

    <ipython-input-29-6792174fccf4>:8: RuntimeWarning: invalid value encountered in sqrt
      y = A*x / (np.sqrt(B-x**2)) + C
    /Users/killianfoley/opt/anaconda3/lib/python3.8/site-packages/scipy/optimize/minpack.py:828: OptimizeWarning: Covariance of the parameters could not be estimated
      warnings.warn('Covariance of the parameters could not be estimated',

    array([  5.   , 113.556,   0.   ])

```python
plt.figure(figsize=(12,8))
plt.plot(x_data, y_data, 'o',linewidth=7, label='original data')
plt.plot(x_data, mbamfunc(x_data, *popt), label='line of best fit')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title('plot of Alternative function vs original data')
plt.legend()
plt.show();
```

Unfortunately there is a difficulty with calculating the required parameters due to negative values in the square root. This would require further investigation.

### Conclusion
This notebook has demonstrated two methods for permorming Simple Linear Regression on a data set. This was then compared with multiple order Polynomial Regression for suitability for the data. Finally further research was conducted on the subject matter and it was found that, increasingly Logistic Regression Equations are used to model the power curve of modern wind turbines.

***
Additional work
#### Regression with sklearn.neighbors.KNeighborsRegressor

```python
# https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsRegressor.html#sklearn.neighbors.KNeighborsRegressor
# Define variables for input set
X = speed.reshape(-1,1)
y = power

#import package
from sklearn.neighbors import KNeighborsRegressor
neigh = KNeighborsRegressor(n_neighbors=5)
neigh.fit(X, y)
```

    KNeighborsRegressor()

Create a new 'output power' column of predicted values for plotting.

```python
# Create new 'power' column of predicted values.
power_predict = neigh.predict(X)
```

#### Plot the result

```python
# plot the original data vs predicted line of best fit
plt.figure(figsize=(12,8))
plt.plot(speed, power, 'o', label='original data')
plt.plot(speed, power_predict, label='line of best fit')
plt.xlabel('speed (m/s)')
plt.ylabel('power (kW)')
plt.title('plot of Alternative function vs original data')
plt.legend()
plt.show();
```

#### Discussion
Removing the anomyly zero power values between approx 17 m/s and 25 m/s should remove the predicted curve spikes

### References
[1] Linear Regression; [Stat.yale.edu](http://www.stat.yale.edu/Courses/1997-98/101/linreg.htm#:~:text=Linear%20regression%20attempts%20to%20model,linear%20equation%20to%20observed%20data.&text=A%20linear%20regression%20line%20has,Y%20is%20the%20dependent%20variable.)

[2] Pearson correlation coefficient; [Wikipedia.org](https://en.wikipedia.org/wiki/Pearson_correlation_coefficient)

[3] Coefficient of determination (R-squared); [Wikipedia.org](https://en.wikipedia.org/wiki/Coefficient_of_determination)

[4] Linear Regression in Python with Scikit-Learn; [Stackabuse.com](https://stackabuse.com/linear-regression-in-python-with-scikit-learn/)

[5] Two Ways to Perform Linear Regression in Python with Numpy and Scikit-Learn; [Codefying.com](https://codefying.com/2016/08/18/two-ways-to-perform-linear-regression-in-python-with-numpy-ans-sk-learn/)

[6] Regression Model Accuracy (MAE, MSE, RMSE, R-squared); [Datatechnotes.com](https://www.datatechnotes.com/2019/02/regression-model-accuracy-mae-mse-rmse.html#:~:text=The%20MSE%2C%20MAE%2C%20RMSE%2C,difference%20over%20the%20data%20set.)

[7] Polynomial Regression; [Wikipedia.org](https://en.wikipedia.org/wiki/Polynomial_regression)

[8] Comparison of logistic functions for modeling wind turbine powercurves; [pdf](https://github.com/killfoley/fundamentalsofDA_project/blob/main/Comparison%20of%20logistic%20functions%20for%20modeling%20wind%20turbine%20power%20curves.pdf)

[9] A Deterministic Bases Piecewise Wind Power Forecasting Models; [pdf](https://github.com/killfoley/fundamentalsofDA_project/blob/main/A%20deterministic%20bases%20piecewise%20wind%20power%20forecasting%20models.pdf)

[10] scipy.optimize.curve_fit; [docs.scipy.org](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html)

#### Further resources
Numpy; [Numpy.org](https://numpy.org/doc/stable/index.html)

Pandas; [Pandas.pydata.org](https://pandas.pydata.org/)

Seaborn; [Seaborn.pydata.org](https://seaborn.pydata.org/index.html)

Scipy; [Scipy.org](https://docs.scipy.org/doc/scipy/reference/index.html)

Matplotlib; [Matplotlib.org](https://matplotlib.org/)

Scikit-Learn; [Scikit-learn.org](https://scikit-learn.org/stable/)

Course notes and Notebooks;


```python
%matplotlib notebook
%matplotlib inline
import math
import matplotlib.pyplot as plt
import numpy as np
```

# Modern Physics

- State the special theory of relativity
- Differentiate inertial and non-inertial reference frames
- Compare classical and relativistic physics approaches
- Calculate relativistic masses
- Calculate time dilation
- Calculate length contraction
- Describe the photoelectric effect
- Calculate Compton scattering angles and kinetic energies
- Calculate de Broglie wavelengths
- Relate energy and wavelength for photons
- Understand wave-particle duality
- Relate wave-particle duality and particle energy/wavelength

## Special Theory of Relativity

Classical physics relies on Newton's laws to descibe motion. Newton's second law says:

\begin{align}
F &=\frac{d\vec{p}}{dt} \\
   &= \frac{dm\vec{v}}{dt}
\end{align}
where
\begin{align}
\vec{F} &= \mbox{the force applied to the object}\\
  \vec{p} &= \mbox{the momentum of the object}\\
  \vec{v} &= \mbox{velocity of the object}\\
  m       &= \mbox{mass of the object}\\
\end{align}

In newtonian physics, the mass of the object ($m$) is constant.

### Relativistic Mass

In 1905 Einstein showed that mass varies with an object's speed.
\begin{align}
m = \frac{m_o}{\sqrt{1-\frac{v^2}{c^2}}}
\end{align}
where
\begin{align}
  m_o &= \mbox{rest mass of the object}\\
  c &= \mbox{speed of light}\\
    &= 3\times10^{8}\frac{m}{s}
\end{align}

#### Exercise: Think, Pair, Share

If one plotted mass as a function of velocity, what could one expect the plot to look like?

## Principle of Relativity

Lots of things are relative.
When we talk in physics about relativity, we intend to refer to the _relative_ features of coordinate systems.

Imagine two inertial coordinate systems. $S$ is stationary, while $S'$ is moving away along the x axis with velocity $\vec{v} = v\hat{x}$. The coordinate transformation is, then.

\begin{align}
x' & = x - vt\\
y' &= y\\
z' &= z\\
t' &= t
\end{align}

Substituting these transformations into Newton's laws does not impact their validity. If we consider a force $F_x$ acting on mass $m$, then the 2nd law in the moving system is:

\begin{align}
F_x & = m\frac{d^2x'}{dt'^2}\\
\end{align}

If we transform it to the stationary system, with constant $v$:

\begin{align}
F_x &= m\frac{d^2x'}{dt'^2}\\
&= m\frac{d^2(x-vt)}{d(t)^2}\\
&= m\frac{d^2x}{dt^2}\\
\end{align}

However, Maxwell's equations don't survive the transformation above. Lorentz observed (1904) that a different transformation could preserve Maxwell's equations. We call this the Lorentz transformation:

\begin{align}
x' &= \frac{x - vt}{\sqrt{1-\frac{v^2}{c^2}}}\\
y' &= y\\
z' &= z\\
t' &= \frac{t-\frac{vx}{c^2}}{\sqrt{1-\frac{v^2}{c^2}}}\\
\end{align}

In the Lorentz transformation above, **space and time depend on one another.**

```python
def x_ltz(x, v, t):
    c = 3.0e8
    num = x - v*t
    denom = math.sqrt(1-(v/c)**2)
    return num/denom

def t_ltz(x, v, t):
    c = 3.0e8
    num = t - v*x/c**2
    denom = math.sqrt(1-(v/c)**2)
    return num/denom

x = 1
vel = 3.0e2
time = np.arange(0, 300, 10)
to_plot = np.arange(0.,30.)
for i in range(0, 30):
    to_plot[i] = x_ltz(x, vel, time[i])

plt.plot(time, to_plot, label="x_ltz")
plt.ylabel("Lorentz transformed x ($m$)")
plt.xlabel("time $(s)$")
plt.legend(loc=2)

```

### Results of the Special Theory of Relativity

What Einstein showed in 1905 was that **all physics in inertial coordinate systems remains unchanged under the Lorentz transformation.** To acheive this, however, one must correct Newton's laws of motion to allow them, too, to remain invariant under this transformation.

Einstein based this on two _postulates_:

- The laws of motion should have the same form in all coordinate systems moving at constant velocities to one another.
- The speed of light in free space, $c$, is the same for all observers and is independent of the relative velocity between the source and observer.

#### Exercise: Think-pair-share

If the first postulate, velocity is kept constant between coordinate systems. What is the name for such coordinate systems?

If the coordinate systems were accelerating with respect to each other, what quality is lost?

### Result: Relativistic Mass

The laws of motion are correct, as stated by Newton, if the mass of the object is a function of the object's speed.

In 1905 Einstein showed that mass varies with an object's speed.

\begin{align}
m = \frac{m_o}{\sqrt{1-\frac{v^2}{c^2}}}
\end{align}
where
\begin{align}
  m_o &= \mbox{rest mass of the object}\\
  c &= \mbox{speed of light}\\
    &= 3\times10^{8}\frac{m}{s}
\end{align}

#### Exercise: Think, Pair, Share

If one plotted mass as a function of velocity, what could one expect the plot to look like?

```python
def m_rel(m_o, v):
    """Returns the relativistic mass of an object

    Parameters
    ----------
    m_o : double
        rest mass of the object
    v : double
        velocity of the object
    """
    c = 3.0e8
    m = m_o/math.sqrt((1 - pow(v,2)/pow(c,2)))
    return m
```

```python
# Plot it
vel = np.arange(0, 3.0e8, 1.0e7)
to_plot = np.arange(0.,30.)
for i in range(0, 30):
    to_plot[i] = m_rel(1, vel[i])

plt.plot(vel, to_plot, label="relativistic mass")
plt.ylabel("relativistic mass (normalized by $m_o$)")
plt.xlabel("velocity $(m/s)$")
plt.legend(loc=2)
```

### Result: Length Contraction

The length of a moving object, in the direction of its motion, appears smaller to an observer at rest:

\begin{align}
L&=L_o \sqrt{1-\frac{v^2}{c^2}}
\end{align}

where

\begin{align}
L_o &= \mbox{proper length of the object at rest}
\end{align}

```python
def l_rel(l_o, v):
    """Returns the relativistic length of an object

    Parameters
    ----------
    l_o : double
        rest length of the object
    v : double
        velocity of the object
    """
    c = 3.0e8
    length = l_o*math.sqrt((1 - pow(v,2)/pow(c,2)))
    return length

# Plot it
vel = np.arange(0, 3.0e8, 1.0e7)
to_plot = np.arange(0.,30.)
for i in range(0, 30):
    to_plot[i] = l_rel(1, vel[i])

plt.plot(vel, to_plot, label="relativistic length")
plt.ylabel("relativistic length (normalized by $L_o$)")
plt.xlabel("velocity $(m/s)$")
plt.legend(loc=2)
```

#### Exercise: Think-Pair-Share

When we talk about length in this way, in what direction are we measuring it?

### Result: Time Dilation

The passage of time appears slow in a system moving with respect to a stationary observer.

\begin{align}
t &= \frac{t_o}{\sqrt{1-\frac{v^2}{c^2}}}
\end{align}

where

\begin{align}
t &= \mbox{time required for some physical phenomenon in the moving system}\\
t_o &= \mbox{time required for some physical phenomenon in the stationary system}
\end{align}

```python
def t_rel(t_o, v):
    """Returns the time required for some physical phenomenon in the moving system

    Parameters
    ----------
    t_o : double
        time required for some physical phenomenon in the stationary system
    v : double
        velocity of the moving reference frame
    """
    c = 3.0e8
    time = t_o/math.sqrt((1 - pow(v,2)/pow(c,2)))
    return time

# Plot it
vel = np.arange(0, 3.0e8, 1.0e7)
to_plot = np.arange(0.,30.)
for i in range(0, 30):
    to_plot[i] = t_rel(1, vel[i])

plt.plot(vel, to_plot, label="relativistic time")
plt.ylabel("relativistic time (normalized by $t_o$)")
plt.xlabel("velocity $(m/s)$")
plt.legend(loc=2)
```

### Exercise: Consider twins

Now, imagine two identical twins, one of whom makes a journey into space in a high-speed rocket and returns home.

Which is older, at the end of the event?

### Result: Equivalence of mass and energy

The most famous result is that there is an equivalence between mass and energy:

\begin{align}
E_{rest} = m c^2
\end{align}

For particles with mass (such as electrons, protons, neutrons, alpha particles, etc.), the rest mass energy is

\begin{align}
E_{rest} = m_o c^2
\end{align}

where m_o is the mass that is given in reference tables.

### Total Energy

The total energy ($E_{total}$) is the sum of the rest and kinetic energies.  Therefore, for relativistic particles, the total energy is:

\begin{align}
E_{total} &= E_{rest} + E_{kinetic}\\
          &= mc^2\\
          &=\frac{m_oc^2}{\sqrt{1-\frac{v^2}{c^2}}}\\
\end{align}

The above can be used for any particle, though for velocities much slower than the speed of light ($<0.1c$), one can use the simpler classical mechanics expression:

\begin{align}
          E_{total} &= E_{rest} + E_{kinetic}\\
                    &=m_o c^2 + \frac{1}{2}m_ov^2\\
\end{align}

### Exercise: Think-pair-share
Why do photons, such as gamma and X rays, have no rest mass energy ?

## Photon Energy

The total energy of a photon, moving at the speed of light $(c=\lambda\nu)$ is:

\begin{align}
E_{total} &= h\nu\\
  &= \frac{hc}{\lambda}
\end{align}

where

\begin{align}
h &=\mbox{Planck's constant}\\
\nu &= \mbox{frequency of the particle}\\
\lambda &= \mbox{wavelength}
\end{align}

## Kinetic Energy and Momentum

The equation for a particle's momentum is identical both classically and relativistically,

\begin{align}
p=mv.
\end{align}

Classically, we can describe the kinetic energy, $T$, using the momentum.

\begin{align}
T &= \frac{mv^2}{2}\\
  &= \frac{p^2}{2m}\\
  \implies p = \sqrt{2mT}
\end{align}

Relativistically, the relationship between momentum and kinetic energy is, instead:

\begin{align}
p = \frac{1}{c}\sqrt{T^2 + 2Tm_oc^2}.
\end{align}

```python
def mom_class(T, m):
    p = pow(2*m*T, 0.5)
    return p

def mom_rel(T, m_o):
    c = 3.0e8
    p = (1/c)*pow((T**2 + 2*T*m_o*c**2), 0.5)
    return p

# Plot it
kinetic = np.arange(0, 3.0e8, 1.0e7)
to_plot_rel = np.arange(0.,30.)
to_plot_class = np.arange(0, 30.)
m = 1
for i in range(0, 30):
    to_plot_rel[i] = mom_rel(kinetic[i], m)
    to_plot_class[i] = mom_class(kinetic[i], m)

plt.plot(kinetic, to_plot_class, label="classical momentum")
plt.plot(kinetic, to_plot_rel, label="relativistic momentum")
plt.xlabel("kinetic energy")
plt.legend(loc=2)
```

```python
to_plot_diff = to_plot_rel - to_plot_class
plt.plot(kinetic, to_plot_diff, label="mom_rel - mom_class")
plt.ylabel("relativistic momentum correction ($\Delta p $)")
plt.xlabel("kinetic energy")
plt.legend(loc=2)
```

## The photoelectric effect

- **1887** Hertz showed that when metal surfaces were irradiated with light "electricity" was emitted
- **1898** J.J. Thompson showed these were electrons ("photoelectrons")

The classical theory explaining this was insufficient to describe the experimental results. Specifically, it failed to explain the following phenomena:

- For each metal there is a minimum light frequency $\nu$ below which no photoelectrons are emitted
- There is no time lag between the irradiation and emission
- The intensity of the light only impacts the _rate_ of photoelectron emission
- The photoelectron kinetic energy only depends on frequency of light (not intensity)

- **1905** Einstein, in his big year, suggested a new model.

He postulated that light is made of _photons_ that have energy:

\begin{align}
E&=h\nu\\
 &=\mbox{energy of a photon}\\
\mbox{where }&\\
h&=\mbox{Plank's constant}\\
 &=6.62\times 10^{-34} [J\cdot s]\\
\nu&=\mbox{photon frequency}
\end{align}

Additionally, he suggested that photons act as a whole -- never partially absorbed or emitted by an atom. Thus, the maximum kinetic energy of an electron would be:

\begin{align}
E&=h\nu-A\\
 &=\mbox{maximum kinetic energy of a photoelectron}\\
 \mbox{where }&\\
A &= \mbox{"work function"}\\
&=\mbox{amount of energy required to free the electron from the metal}
\end{align}

## Exercise: Photoelectric effect (from Shultis & Faw)

What is the maximum wavelength of light required to liberate photoelectrons from a metallic surface with a awork function of 2.35ev (energy neeced to free a valence electron)?

The maximum wavelength has the minumum frequency. So, find the minimum frequency by assuming no energy is lost to the electron in the form of kinetic energy:

\begin{align}
\nu_{min} &= \frac{A}{h}\\
          &=\frac{2.35ev}{4.136\times10^{-15}eV}\\
          &= 5.68\times 10^{14} \frac{1}{s}\\
\implies \lambda_{max} &= \frac{c}{\nu_{min}}\\
            &=\frac{2.998\times10^{8}\frac{m}{s}}{5.68\times 10^{14}\frac{1}{s}}\\
             &=\boxed{5.28\times10^{-7}m}
\end{align}

## Compton Scattering

- **1922** Compton noticed that x-rays scattered from electrons had a change in wavelength $\Delta\lambda = \lambda' - \lambda$ proportional to $(1-\cos{\theta_s})$

To explain this, we must treat x-rays as particles with a linear momentum $p=\frac{h}{\lambda}$ and energy $E=h\nu=pc$.

In an x-ray scattering  interaction, both momentum and energy must be conserved. To conserve momentum

\begin{align}
\vec{p_\lambda} = \vec{p_{\lambda'}}+\vec{p_e}
\end{align}

## Exercise: Conservation of Momentum

Draw a triangle representing the relationship between $\vec{p_\lambda}$,$\vec{p_{\lambda'}}$, and $\vec{p_e}$. Use $\phi_e$ and $\theta_s$ to represent the electron-photon incident angle and the scattering angle.

```python

```

From the law of cosines:

\begin{align}
p_e^2 &= p_\lambda^2 + p_{\lambda'}^2 - 2p_\lambda p_{\lambda'}\cos{\theta_s}
\end{align}

From conservation of energy:
\begin{align}
p_\lambda c+m_ec^2 &=  p_{\lambda'}c + mc^2\\
\mbox{where }&\\
m_e&=\mbox{rest mass of the electron}\\
m &= \mbox{relativistic electron mass after scattering}
\end{align}

Combining these gives:

\begin{align}
\lambda' - \lambda &= \frac{h}{m_ec}(1-\cos{\theta_s})\\
\implies \frac{1}{E'} - \frac{1}{E} &= \frac{1}{m_ec^2}(1-\cos{\theta_s})
\end{align}

## Exercise: Recoil energy

What is the recoil kinetic energy of the electron?

First, we can find the energy of the scattered photon:

\begin{align}
E'  &= \left[\frac{1}{E} + \frac{1}{m_ec^2}(1-\cos{\theta_s})\right]^{-1}\\
  &= \left[\frac{1}{3MeV} + \frac{1}{0.511MeV}\left(1-\cos{\frac{\pi}{4}}\right)\right]^{-1}
  &= 1.10MeV
\end{align}

The energy lost by the scattered photon is balanced by kinetic energy of the electron, $ T_e = E-E' = 3- 1.10 = 1.90MeV.$

## Electromagnetic Radiation : Wave-Particle duality

### Photon properties
Photons must always be treated relativistically since they travel at the speed of light $c$.

#### What's $\nu$?

\begin{align}
c = \lambda \nu\\
\implies \nu = \frac{c}{\lambda}
\end{align}

The momentum of the photon is of course:

\begin{align}
p&=\frac{E}{c}\\
&= \frac{h\nu}{c}\\
&= \frac{h}{\lambda}.
\end{align}

And its relativistic mass comes from the equivalence of mass and energy:

\begin{align}
mc^2 &= E = h\nu\\
\implies m&=\frac{h\nu}{c^2}
\end{align}

## de Broglie wavelength

- **1924** de Broglie's PhD thesis proposed that electrons have wave-like and particle-like properties, just like photons.

The dominance of classical vs relativistic behavior is related to the object's energy and mass. The de Broglie wavelength can be used to differentiate that threshold.

By rearranging the momentum equation stated for photons, a relationship between $\lambda$ and $p$ for the electron can be found:

\begin{align}
\lambda &={\frac {h}{p}}\\
 &= \frac{h}{\sqrt{T^2 + 2Tm_oc^2}}
\end{align}

The relationship is now known to hold for all types of matter: **all matter exhibits properties of both particles and waves.**

```python

```