# Notebook from annacuomo/CellRegMap_analyses
Path: simulations/notebooks/sc_slmm_predict_GxE_effects.ipynb

<code>
from numpy_sugar.linalg import economic_qs, economic_qs_linear
from numpy.random import RandomState, default_rng
from numpy import arange, concatenate, newaxis, median, asarray
from glimix_core.lmm import LMM
from scipy.stats import chi2
from numpy_sugar import epsilon
from numpy import asarray, clip, inf, ones, sqrt
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

from struct_lmm2 import StructLMM2, create_variances, sample_phenotype_gxe_____no_output_____import struct_lmm2 # check that it refers to code in repo
struct_lmm2_____no_output_____random = default_rng(20)

n_individuals = 100

maf_min = 0.10
maf_max = 0.45

n_snps = 100
# n_snps = 500

# n_cells = 100
# n_cells = 10
# n_cells = 2
n_cells = arange(n_individuals) + 1

n_env_groups = 10
offset = 0.3

# indices of causal SNPs
g_causals = [5, 6]
gxe_causals = [10, 11]

# weight of genetic variance explained by GxE
r0 = 0.5
# r0 = 0
# r0 = 1

# total variance explained by genetics (G + GxE)
v0 = 0.5
# v0 = 0

v = create_variances(r0, v0)_____no_output_____s = sample_phenotype_gxe(
        offset=offset,
        n_individuals=n_individuals,
        n_snps=n_snps,
        n_cells=n_cells,
        n_env_groups=n_env_groups,

        maf_min=maf_min,
        maf_max=maf_max,
        g_causals=g_causals,
        gxe_causals=gxe_causals,
        variances=v,
        random=random,
    )_____no_output_____# kinship matrix (block diagonal)
# plot for few individuals to check if it looks good
plt.matshow(s.K)_____no_output_____plt.matshow(s.E @ s.E.T)_____no_output_____# set up model
# covariates (just ones here)
M = ones((s.y.shape[0], 1))_____no_output_____y = s.y.reshape(s.y.shape[0],1)_____no_output_____slmm2 = StructLMM2(y, M, s.E, s.Ls)_____no_output_____ge = slmm2.predict_interaction(s.G, s.mafs)_____no_output_____# 5050 cells, 100 SNPs
s.G.shape_____no_output_____# beta_G value for each of the 100 SNPs
beta_G = ge[0]
beta_G.shape_____no_output_____# beta_GxE values (should be n_SNPs x n_cells, or viceversa)
beta_GxE = ge[1][0]
beta_GxE.shape_____no_output_____beta_GxE_____no_output_____import numpy as np
from math import ceil
import matplotlib.pyplot as plt
##
beta = np.array([])
for i in range(beta_GxE.shape[1]):
# for i in range(5):
    # get single-cell effect sizes
    v = beta_GxE[:,i]
    # get min and max
    ymin = min(v)
    ymax = max(v)
    # rank values
    order = v.argsort()
    y = v[order]
    x = range(len(v))
    plt.scatter(x,y)
    # define 10% of cells
    xx = ceil(0.1*len(v))
    plt.vlines(x=xx,ymin=ymin, ymax=ymax)
    plt.hlines(y=y[xx],xmin=0, xmax=len(v))
    plt.vlines(x=len(v)-xx,ymin=ymin, ymax=ymax)
    plt.hlines(y=y[len(v)-xx],xmin=0, xmax=len(v))
    # add title
#     plt.title(df.columns.values[i])
    plt.title(str(i))
    plt.show()
    beta = np.append(beta,y[len(v)-xx]-y[xx])_____no_output_____plt.hist(beta)
plt.show()_____no_output_____beta.min()_____no_output_____beta.mean()_____no_output_____beta.max()_____no_output_____## expect 10, 11 (causal GxE) to be outliers_____no_output_____beta[10]_____no_output_____beta[11]_____no_output_____
</code>


# Notebook from tashley/Relaxing-Channel-Experiment-Workflows
Path: processing_raw_topography_data.ipynb

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage.filters import sobel
import glob
from tqdm import tqdm
import matplotlib as mpl
import seaborn as sns
import os
%matplotlib inline_____no_output_____

# Raw data

Each elevation model is constructed from nine separate 1 mm resolution scans made with the SICK Ranger instrument. The scans are overlapping so that there are between three and nine measurements of bed elevation for each 1mm by 1mm grid cell. Each pass spans a maximum of 90 cm, and the data can be noisy when ambient light is reflected off the water surface. The algorithm below combines the nine noisy scans to produce a single topography model._____no_output_____

# Import example data
scanfiles = glob.glob(os.path.join('data','topography_example', '*.DAT'))

raw_data = np.empty((1501, 2688, 9), 'float')
raw_data *= np.nan

for j in range(9):

    # Load scan and reshape to 2D array
    with open(scanfiles[j], 'rb') as f:
        raw = np.fromfile(f, np.float32).reshape(901, 2688) + 785

    # Populate raw_data matrix with scans transformed to correct position
    if j%3 == 0:
        raw_data[:901,:,j%9] = raw
    elif j%3 == 1:
        raw_data[300:1201,:,j%9] = raw
    else:
        raw_data[600:1501,:,j%9] = raw

raw_data[raw_data==-9214.0] = np.nan # Instrument assigns numeric value of -9214 to represent NaN_____no_output_____fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(14,8))
plt.subplots_adjust(right=0.89)
cax = plt.axes([0.9, 0.25, 0.01, 0.5])

# Plot all scans in their own axes
for ix in range(9):
    i = ix//3
    j = ix%3

    ax[i,j].set_xticks([])
    ax[i,j].set_yticks([])
    im = ax[i,j].imshow(raw_data[:,:,ix], vmin=0, vmax=150)
    ax[i,j].set_title('Scan {}'.format(ix+1))

# make colorbar
cmap = mpl.cm.viridis
norm = mpl.colors.Normalize(vmin=0, vmax=150)
cb1 = mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm)
cb1.set_label('Elevation above baselevel (mm)')
cb1.set_ticks([0, 50, 100, 150])
cb1.set_ticklabels([r'$\leq$ 0', 50, 100, r'$\geq$ 150'])

# add red rectangle corresponding to example region (below)
ax[0,0].add_patch(mpl.patches.Rectangle((500, 200),
                        1000, 500,
                        fc ='none',
                        ec = sns.color_palette()[3],
                        lw = 3))

# Make scale bar
ax[0,0].plot([500, 1500], [1300, 1300], 'k', lw=3)
ax[0,0].text(500, 1200, '1 m')_____no_output_____

The SICK Ranger instrument returns NaN (white in the figures above and below) outside of the 90 cm window. It also returns NaN when it is unable to identify the bed surface. The image below shows bad data in the boxed region in Scan 1 above. Note that elevations less than zero are not possible because base level is defined with respect to the stream table surface._____no_output_____

fig, ax = plt.subplots(figsize=(10, 5))

# Plot first scan
im = ax.imshow(raw_data[:,:,0], vmin=0, vmax=150)

# Make colorbar
cb = plt.colorbar(im)
cb.set_label('Elevation above baselevel (mm)')
cb.set_ticks([0, 50, 100, 150])
cb.set_ticklabels([r'$\leq$ 0', 50, 100, r'$\geq$ 150'])

# Crop to example region
ax.set_xlim(500, 1500)
ax.set_ylim(700, 200)

# Format figure
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel('1 m')
ax.set_ylabel('50 cm')
ax.set_title('Example Region: Raw Data')_____no_output_____

# Identify bad data by threshold elevation and gradient

Elevations less than zero and greater than 15 cm are not possible.

Eliminating pixels with gradients larger than 5 (i.e. the difference between adjacent pixels is larger than 5 mm) and then interpolating eliminates isolated bad datapoints while preserving near-vertical regions of topography created by undercutting and bank collapse._____no_output_____

def clean_scans(raw):

    # Make a copy
    cleaned = raw.copy()

    # assign numeric value to nan
    cleaned[np.isnan(cleaned)] = -9999

    # set impossible data to consistent value
    cleaned[cleaned < 0] = -9999
    cleaned[cleaned > 150] = -9999

    # calculate gradient and label regios that are surrounded by large gradients (islands)
    grad = sobel(cleaned)
    cleaned[grad>5] = -9999

    # return negative values to nan
    cleaned[cleaned<=0] = np.nan

    return grad, cleaned

# Run and store results
filtered = np.empty_like(raw_data)
gradient = np.empty_like(raw_data)
for i in range(9):
    gradient[:,:,i], filtered[:,:,i] = clean_scans(raw_data[:,:,i])_____no_output_____fig, ax = plt.subplots(nrows=2, figsize=(10, 10))

# Plot regions identified by threshold gradient
ax[0].set_title('Example Region: Gradient > 5')
ax[0].imshow(gradient[:,:,0]>5)

# Plot cleaned data
ax[1].set_title('Example Region: Bad Data Removed')
ax[1].imshow(filtered[:,:,0], vmin=0, vmax=150)

for i in [0,1]:
    # Crop to example region
    ax[i].set_xlim(500, 1500)
    ax[i].set_ylim(700, 200)

    # Format axes
    ax[i].set_xticks([])
    ax[i].set_yticks([])

# Plot example locations for subsequent analysis
ax[1].scatter(805, 605, marker='*', s=500, c=sns.color_palette()[3], label='Noisy Data Example')
ax[1].scatter(905, 385, marker='*', s=500, c='k', label='Optimal Measurement Conditions Example')
ax[1].legend()*c* argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with *x* & *y*.  Please use the *color* keyword-argument or provide a 2D array with a single row if you intend to specify the same RGB or RGBA value for all points.

# Downsample to 1 cm resolution

Initially, all measurements (up to 900 per 1 cm $\times$ 1 cm cell) are retained._____no_output_____

def downsample(arr, resratio):
    newshape = [arr.shape[0]//resratio, arr.shape[1]//resratio, 9*resratio**2]
    out = np.empty(newshape)
    for i in range(newshape[0]):
        for j in range(newshape[1]):
            out[i,j] = arr[i*resratio:(i+1)*resratio, j*resratio:(j+1)*resratio].ravel()

    return out

original_resolution = 1 # mm per px
downsampled_resolution = 10 # mm per px

resolution_ratio = downsampled_resolution // original_resolution  # must be integer

# run on filtered raw data
downsampled = downsample(filtered, resolution_ratio)

print(filtered.shape)
print(downsampled.shape)(1501, 2688, 9)
(150, 268, 900)

# Merging samples to estimate bed elevation

We assume measurements of bed elevation $\eta'$ follow a normal distribution under optimal conditions i.e.:

$$
\eta' \sim \mathcal{N}(\eta, \sigma)
$$

where $\eta$ is the true bed elevation and $\sigma$ is the standard deviation of the measurement uncertainty.

We find that $\sigma \approx 0.5$ for regions where data quality is good. The figure below shows elevation measurements in the location of the black star above._____no_output_____

# Example data under optimal conditions in a region covered by 6 passes (N = 600)
sample = downsampled[90, 38]
fig, ax = plt.subplots()

sns.histplot(sample, ax=ax, kde=True, color=sns.color_palette()[0],
             label=r'$\sigma = {:.4f}, N={:d}$'.format(np.nanstd(sample), len(sample[~np.isnan(sample)])))

sns.rugplot(sample, ax=ax, color=sns.color_palette()[0])

ax.set_xlabel('Measured elevation (mm)')
ax.legend()_____no_output_____

## Outlier detection and averaging
Bed elevation is estimated by averaging points points that lie within the maximum density window of width $2\sigma$. In the example below, bed elevation is calculated for the location indicated by the red star above._____no_output_____

# Example application of outlier detection and averaging in a location with noisy data

# Get sample for starred location
sample = downsampled[60, 80]

# Sort and remove nans
ss = np.sort(sample[~np.isnan(sample)])

# Compute number of samples between val and val+2std for every sample value
std = 0.25 #mm
counts = [np.sum((ss > sample_i) & (ss < sample_i+4*std)) for sample_i in ss]

# Get argument of maximum (corresponds to lower bound of window)
arg0 = np.argmax(counts)

# Value of lower bound
minrng = ss[arg0]

# Value of upper bound
maxrng = minrng+4*std

# Argument of first element that is larger than upper bound (indexing goes to arg1 - 1)
arg1 = np.argmax(ss>maxrng)

if arg1==0: # occurs when largest sample is within the range
    subsamp = ss[arg0:]
else:
    subsamp = ss[arg0:arg1]

# Calculate mean with outliers
badmean = np.nanmean(ss)

# Calculate mean without outliers
mean = np.nanmean(subsamp)

fig, ax = plt.subplots()
sns.kdeplot(ss, ax=ax, label='Full Sample', color=sns.color_palette()[0])
sns.kdeplot(subsamp, ax=ax, label = 'Outliers Removed', color=sns.color_palette()[1])
sns.rugplot(ss, ax=ax, c=sns.color_palette()[0])
sns.rugplot(subsamp, ax=ax, c=sns.color_palette()[1])

ax.plot([badmean, badmean], [0, 1.6], 'k--', label='Mean with outliers')
ax.plot([mean, mean], [0, 1.6], 'k', label='Mean without outliers')
ax.set_ylim(0, 1.6)
ax.set_xlim(30, 55)
ax.set_xlabel('Elevation (mm)')
ax.legend()_____no_output_____# Implements logic above as a function
def calcmean(sample, std):
    ss = np.sort(sample[~np.isnan(sample)])

    if len(ss)==0:
        return np.nan, 0

    else:
        counts = [np.sum((ss > sample_i) & (ss < sample_i+4* std)) for sample_i in ss]
        arg0 = np.argmax(counts)
        minrng = ss[arg0]
        arg1 = np.argmax(ss>minrng+4*std)
        count = counts[arg0]

        if arg1==0:
            subsamp = ss[arg0:]
        else:
            subsamp = ss[arg0:arg1]

        mean = np.nanmean(subsamp)

        return mean, count_____no_output_____# Create empty arrays for elevation and sample size information
elev = np.empty_like(downsampled[:,:,0])
count = np.empty_like(elev)

# iterate all locations
for ix in tqdm(range(elev.size)):

    # unpack indices (necessary to track progress with tqdm)
    i, j = ix//downsampled.shape[1], ix%downsampled.shape[1]

    # calculate and store mean elevation and sample size
    elev[i,j], count[i,j] = calcmean(downsampled[i,j], std=0.25)100%|███████████████████████████████████████████████████████████████████████████| 40200/40200 [04:50<00:00, 138.37it/s]

# Filtering bad elevation estimates based on sample size

The number of samples contributing to the average after removing outliers is good measure of data quality. Every location on the bed has the potential for between 300 and 900 measurements. A threshold minimum of 30 measurements provides a good balance between eliminating bad data and preserving good data._____no_output_____

# Create a copy
filtered_elev = elev.copy()

# Set elevations where n < 30 to nan
filtered_elev[count<30] = np.nan_____no_output_____fig, ax = plt.subplots(nrows=4, figsize=(6,14), sharex = True, sharey=True)

# Plot elevation estimates from above
ax[0].set_title('Example Region: Estimated bed elevation')
ax[0].imshow(elev, vmin=0, vmax=150)

# Plot arrow indicating bad data
ax[0].arrow(66, 38, 10, 15, width=1, facecolor=sns.color_palette()[3])
ax[0].text(67, 37, 'Bad Data', size=12)

# Plot sample size map
ax[1].set_title('Example Region: Number of good samples')
im1=ax[1].imshow(count)

# make colorbar for sample size
plt.subplots_adjust(right=0.88)
cax = plt.axes([0.9, 0.52, 0.02, 0.15])
cmap = mpl.cm.viridis
norm = mpl.colors.Normalize(vmin=0, vmax=900)
cb1 = mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm)
cb1.set_label('Count')

# Plot regions identified by threshold sample size
ax[2].set_title('Example Region: Locations where N < 30')
ax[2].imshow(count<30)

# Plot cleaned elevation data
ax[3].set_title('Example Region: Elevation map with N<30 Removed')
ax[3].imshow(filtered_elev)

for i in range(4):
    ax[i].set_xticks([])
    ax[i].set_yticks([])
    ax[i].set_xlim(50, 150)
    ax[i].set_ylim(70, 20)
    _____no_output_____

# Fill missing values

Missing elevation values are filled using adjacent valid elevations from the same cross section. Using the minimum adjacent elevation (rather than interpolating linearly) produces the best results because missing values tend to be located next to large elevation differences._____no_output_____

def interp_nans(Zin):

    # Create empty array with correct shape
    Zout = np.empty_like(Zin)

    # Iterate over all positions
    for i in range(Zin.shape[0]):
        for j in range(Zin.shape[1]):

            # If the value is missing...
            if np.isnan(Zin[i,j]):

                # Get list of elevations moving left and right from target location
                Zright = Zin[i+1:,j]
                Zleft = Zin[i-1::-1,j]

                # Get first valid elevation to right
                if len(Zright > 0) and (~np.isnan(Zright)).any():
                    Z1 = Zright[np.argmax(~np.isnan(Zright))]
                else:
                    Z1 = np.nan

                # Get first valid elevation to left
                if (len(Zleft)> 0) and (~np.isnan(Zleft)).any():
                    Z2 = Zleft[np.argmax(~np.isnan(Zleft))]
                else:
                    Z2 = np.nan

                # Assign minimum
                Zout[i,j] = np.nanmin([Z1, Z2])

            else:
                Zout[i,j] = Zin[i,j]

    return Zout

# Apply to filtered
Zfinal = interp_nans(filtered_elev)_____no_output_____fig, ax = plt.subplots(nrows=3, figsize=(8,12))

# Plot elevation data with N<30 removed
ax[0].set_title('Final Elevation Data')
ax[0].imshow(filtered_elev, vmin=0, vmax=150)
ax[0].set_ylim(15, 135)

# Plot elevation data with missing values filled
ax[1].set_title('Missing Values Filled')
ax[1].imshow(Zfinal, vmin=0, vmax=150)
ax[1].set_ylim(135, 15)
ax[1].plot([200, 200], [135, 15], 'k--')

# Plot rectangle corresponding to example region above
ax[1].add_patch(mpl.patches.Rectangle((50, 20),
                            100, 50,
                            fc ='none',
                            ec = sns.color_palette()[3],
                            lw = 2))

# Plot example region filled
ax[2].set_title('Example Region')
ax[2].imshow(Zfinal, vmin=0, vmax=150)
ax[2].set_xlim(50, 150)
ax[2].set_ylim(70, 20)

for i in [0,1,2]:
    ax[i].set_xticks([])
    ax[i].set_yticks([])_____no_output_____

# Plot an example cross-section

Corresponds to the black dashed line in the previous figure_____no_output_____

fig, ax = plt.subplots(nrows=2, figsize=(10, 10))

# Plot raw data
for i in range(9):
    for j in range(10):
        ax[0].plot(np.linspace(0.05, 119.95, 1200), raw_data[150:1350, 2000+j, i]/10, c='k', alpha=0.03)
        ax[1].plot(np.linspace(0.05, 119.95, 1200), raw_data[150:1350, 2000+j, i]/10, c='k', alpha=0.03)

# Plot final data
ax[1].plot(np.linspace(0.5, 119.5, 120), Zfinal[15:135,200]/10, c=sns.color_palette()[3])

ax[0].set_title('Example Cross-Section: Raw Data (3% transparency)')
ax[1].set_title('Example Cross-Section: Raw and Final (Red)')

ax[0].set_ylabel('Bed Elevation (cm)')
ax[1].set_ylabel('Bed Elevation (cm)')
ax[1].set_xlabel('Cross-Stream Position (cm)')

ax[0].set_ylim(0, 15)
ax[0].set_xlim(0, 120)
ax[1].set_ylim(0, 15)
ax[1].set_xlim(0, 120)_____no_output_____


# Notebook from OxfordRSE/pyross
Path: examples/deterministic/ex06-SEIR.ipynb

## The SEIR model

The SEIR model of epidemiology partitions the population into three compartments: susceptibles, S, who can catch the disease; exposed, E, that has caught the infection but is not infectious;  infectives, I, who have already caught the disease and infect susceptibles; and recovered individuals, R. Since the disease is assumed not to be fatal, the sum $N=S+I+R$ remains constant. The rate at which the susceptibles get infected is
$$
\lambda(t) = \frac{\beta I}{N}
$$
where the parameter $\beta$ is the probability of infection on contact. The infected individuals recover from the disease at a rate $\gamma$. Then, the ordinary differential equations of the SIR model are

\begin{align}
\dot S &= -\lambda(t)S \\
\dot E &= \lambda(t)S - \gamma_E E \\
\dot I &= \gamma_E E - \gamma I \\
\dot R &= \gamma I
\end{align}

Here $ 1/\zeta$ can be interpreted as the average incubation period. This example integrates the above equations to obtain what is called the **epidemic curve**: a plot of the number of susceptibles and infectives as a function of time. _____no_output_____

<code>
%%capture
## compile PyRoss for this notebook
import os
owd = os.getcwd()
os.chdir('../../')
%run setup.py install
os.chdir(owd)_____no_output_____%matplotlib inline
import numpy as np
import pyross
import matplotlib.pyplot as plt
#from matplotlib import rc; rc('text', usetex=True)_____no_output_____M = 1                  # the SIR model has no age structure
Ni = 1000*np.ones(M)   # so there is only one age group
N = np.sum(Ni)         # and the total population is the size of this age group

alpha = 0              # fraction of asymptomatic infectives
beta  = 0.2            # infection rate
gIa   = 0.1            # recovery rate of asymptomatic infectives
gIs   = 0.1            # recovery rate of symptomatic infectives
gE    = 0.04           # recovery rate of E
fsa   = 1              # the self-isolation parameter

E0  = np.array([0])
Ia0 = np.array([0])     # the SIR model has only one kind of infective
Is0 = np.array([1])     # we take these to be symptomatic
R0  = np.array([0])     # and assume there are no recovered individuals initially
S0  = N-(Ia0+Is0+R0+E0)    # so that the initial susceptibles are obtained from S + Ia + Is + R = N

# there is no contact structure
def contactMatrix(t):
    return np.identity(M)

# duration of simulation and data file
Tf = 500;  Nt=160;

# instantiate model
parameters = {'alpha':alpha, 'beta':beta, 'gIa':gIa, 'gIs':gIs, 'gE':gE, 'fsa':fsa}
model = pyross.deterministic.SEIR(parameters, M, Ni)

# simulate model
data=model.simulate(S0, E0, Ia0, Is0, contactMatrix, Tf, Nt)_____no_output_____# plot the data and obtain the epidemic curve

S  = data['X'][:,0].flatten()
E  = data['X'][:,1].flatten()
Ia = data['X'][:,2].flatten()
Is = data['X'][:,3].flatten()
t = data['t']

fig = plt.figure(num=None, figsize=(10, 8), dpi=80, facecolor='w', edgecolor='k')
plt.rcParams.update({'font.size': 22})

plt.fill_between(t, 0, S/N, color="#348ABD", alpha=0.3)
plt.plot(t, S/N, '-', color="#348ABD", label='$S$', lw=4)

plt.plot(t, E/N, '-', color="green", label='$E$', lw=4)
plt.fill_between(t, 0, E/N, color='green', alpha=0.3)

plt.fill_between(t, 0, Is/N, color='#A60628', alpha=0.3)
plt.plot(t, Is/N, '-', color='#A60628', label='$I$', lw=4)

R=N-S-Ia-Is; plt.fill_between(t, 0, R/N, color="dimgrey", alpha=0.3)
plt.plot(t, R/N, '-', color="dimgrey", label='$R$', lw=4)

plt.legend(fontsize=26); plt.grid()
plt.autoscale(enable=True, axis='x', tight=True)_____no_output_____
</code>


# Notebook from 2-science/Binder_test
Path: radiationSunTeacher.ipynb

# Solar Radiation

© Dimitrios Theodorakis GNU General Public License v3.0 https://github.com/DimitriosAstro/Astronomy_____no_output_____

import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Image
%matplotlib inline_____no_output_____

### AIM - Visualise the blackbody radiation from different temperature suns and calculate the effective temperature of planets.

**Predict**

Have a think about these questions and make some predictions! Be sure to tell someone else what you predict.

1) Do hotter objects emit more longer or shorter wavelengths?
2) What colour light does our sun emit the most of?

# Let's go: The Multi-Wavelength Sun

We can approximate the sun as a black body (an object that absorbs and emits radiation at all frequencies).
The sun emits black-body radiation. This is radiation of all frequencies in the electromagnetic spectrum.
It doesn't emit the same amount of radiation for each frequency though - we know this because hot stars look blue and cooler stars red.
Each black body has a peak of its radiation curve - this peak tells us what frequency of radiation is emitted the most.

Let's visualise the black-body radiation from the sun:_____no_output_____

T = 5772 # K
kb = 1.380649*10**(-23) # J/K
c = 299792458 # m/s
h = 6.62607015*10**(-34) # Js

l = np.arange(0.01,3,0.01)
# l in in micrometres, convert it to metres
# then create an Array, B, of zeros the same length of l
# Your code here:
l = l*10**(-6)
B = np.zeros(len(l))

for i in range(len(l)):
    B[i] = 2*h*c**2/l[i]**5 * 1/(np.exp(h*c/(l[i]*kb*T))-1)

fig = plt.figure(2)
ax = plt.subplot(xlim=(0,3),ylim=(0,3))
ax.plot(l*10**6, B/10**13, c="gold")
ax.set_xlabel("Wavelength / micrometer")
ax.set_ylabel("Spectral Intensity / 10^13 W/sr/m^3")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)_____no_output_____

You can see a shift to higher intensity and lower wavelength (higher energy) radiation for higher temperature curves.
The peak wavelength shown on the graph can be calculated using Wein's Law:

$\lambda_{peak} = \frac{b}{T}$

where $b = 2.897771955\times10^{-3}\ mK$.
Let's calculate the lambda+peak for our sun and check the graph is correct:_____no_output_____

b = 2.897771955*10**(-3) # m K
# use Wein's law to calculate the peak wavelength of the sun, what colour is this?
# Your code here:
lp = b/T

print("The peak wavelength is : {:.0f} nm".format(lp*10**9))The peak wavelength is : 502 nm

502 nm just as expected! But wait, this is a wavlength of green blue not yellow like our sun is.
Don't forget the sun radiates other wavelengths as well. The longer tail on the right of the graph to the redder wavelengths means even though the peak wavelength is green overall the sun looks yellow.

Before we move on to get more images let's look at the Stefan-Boltzmann Law.
We saw in the last graph that hotter stars radiate more and are therefore more luminous. But by how much?
The Stefan-Boltzmann Law relates a star's temperature and radius to it's luminosity (the amount of energy emitted per second usually):

$L = 4\pi R^2\sigma T_{e}^{4}$

Here sigma is the Stefan-Boltzman constant and $T_{e}$ is the effective temperature. Te is the temperature of a blackbody that would emit the same amount of radiation as the object or star.
Let's calculate the luminosity of the sun using this law:_____no_output_____

sigma = 5.670374419*10**(-8) # W m^-2 K^-4
R = 6.957*10**8 # m
# use Stefan-Boltzman's law above to calculate the luminosity of the sun
# Your code here:
Lsun = 4*np.pi*R**2*sigma*T**4

print("The Luminosity of the sun is : {:.2e} W".format(Lsun))The Luminosity of the sun is : 3.83e+26 W

We get very close to the accepted value of $3.828\times10^{26}\ W$.
https://nssdc.gsfc.nasa.gov/planetary/factsheet/sunfact.html

Of course the sun is not a perfect black body which we have assumed throughout this section.
If were to plot observational data for the sun on our graph from earlier it would follow the gold curve but with dips and spikes.
These are atomic absorption and emissions lines which we will look at in a future Notebook.

# Warming the Planets

The sun's radiation warms the planets. If we approximate the planets also as black bodies we can calculate their equilibrium temperature.
This is the temperature a planet would be from just solar heating by absorbing all incident solar radiation and emitting it all as well (remember blackbodies emit and absorb radiation perfectly).
The equilibrium temperature is achieved when the absorbed radiation is equal to the emitted radiation of the planet (gaining energy from radiation as fast as it is loosing it).
The power the planet recieves is:

$P_{in} = L_{\odot}(1-a)(\frac{\pi R_{p}^{2}}{4\pi D^2})$

$P_{in} = 4\pi R_{\odot}^{2}\sigma T_{\odot}^{4}(1-a)(\frac{\pi R_{p}^{2}}{4\pi D^2})$

This is the luminosity of the sun times the fraction of light that is absorbed by the planet $(1-a)$. The final term is the area of the planet divided by the area of the sphere whos radius is the distance of the planet to the sun. It's essentially the amount of sunlight that reaches the planet since the radiation spreads out after leaving the solar surface according to the inverse square law.

The power radiated from the planet is found using the stefan boltzmann law, $P_{out} = 4\pi R_p^2\sigma T_{p}^{4}$.
Equating $P_{in}$ and $P_{out}$ we get:

$T_{p} = T_{\odot}(1-a)^{\frac{1}{4}}\sqrt{\frac{R_{\odot}}{2D}}$

Here a is the albedo of the planet which is how much incident radiation is reflected back into space and not absorbed.
Objects with icier or whiter surfaces have a higher albedo since ice and white objects reflect more light than darker objects._____no_output_____

aEarth = 0.306
Tsun = T
Rsun = R
AU = 149597870700 # m
KtodegC = 273.15
degSymb = '\u00b0'

dEarth = 1 * AU
# use the equation above to calculate the effective temperature of the Earth
# Your code here:
TeqEarth = Tsun*(1-aEarth)**0.25*np.sqrt(Rsun/2/dEarth)

print("The Equilibrium Tmperature of the Earth is: {:.0f} K".format(TeqEarth))
print("The Equilibrium Tmperature of the Earth is: {:.0f} {}C".format(TeqEarth-KtodegC,degSymb))The Equilibrium Tmperature of the Earth is: 254 K
The Equilibrium Tmperature of the Earth is: -19 °C

Wow chilly! This temperature doesn't take into account internal planetary heating or the greenhouse effect so it is lower than expected.

# Challenge

 1) Recreate my blackbody curve image
 2) Plot the actual solar spectrum using data from https://data.nodc.noaa.gov/cgi-bin/iso?id=gov.noaa.ncdc:C00899
    You will get something like this: https://en.wikipedia.org/wiki/File:EffectiveTemperature_300dpi_e.png
 3) Calculate the temperature at Mars, Venus, and Jupiter like we did for the Earth
    How do the values compare with the actual average surface temperatures?

# References and Resources

Mihos, C. (2020) Stars and Planets, Url: http://burro.case.edu/Academics/Astr221/SolarSys/equiltemp.html_____no_output_____# Interactives

Use these interactives to see how changing multiple variables alters the outcome.

## Wien's Law

The slider changes the Temperature of the star in K_____no_output_____

from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets

@interact(T=(1,10000))
def weins(T):
    b = 2.897771955*10**(-3) # m K
    lp = b/T
    print("The peak wavelength for temp {:.0f} K is : {:.0f} nm".format(T, lp*10**9))_____no_output_____

## Luminosity using Stefan-Boltzman's Law

The first slider Rsol changes the radius of the star in units of solar radii.
The second slider changes the temperature of the star in K._____no_output_____

@interact(Rsol=(0.5,30,0.1),Temp=(2500,10000,1))
def lumin(Rsol,Temp):
    sigma = 5.670374419*10**(-8) # W m^-2 K^-4
    Tsun = 5772 # K
    Rsun = 6.957*10**8 # m
    R = Rsun*Rsol
    T = Temp
    Lstar = 4*np.pi*R**2*sigma*T**4
    Lsun = 4*np.pi*Rsun**2*sigma*Tsun**4
    ratio = Lstar/Lsun
    print("The Luminosity of the star is : {:.2e} W or {:.2f} times that of the sun".format(Lsun,ratio))_____no_output_____

# Equilibrium Temperature

a is the albedo of the body.
dist is the distance the body is from its star in AU.
Tstar is the temperature of the star in K.
Rstar is the radius of the star in solar radii._____no_output_____

@interact(a=(0,1,0.1),dist=(0.1,50,0.1),Tstar=(2500,10000,1),Rstar=(0.5,30,0.1))
def eqT(a, dist, Tstar, Rstar):
    Rsun = 6.957*10**8 # m
    R = Rstar*Rsun
    AU = 149597870700 # m
    KtodegC = 273.15
    degSymb = '\u00b0'
    d = dist * AU
    eqT = Tstar*(1-a)**0.25*np.sqrt(R/2/d)
    print("The Equilibrium Temperature of this body is: {:.0f} K or {:.0f} {}C".format(eqT, eqT-KtodegC,degSymb))_____no_output_____

## Blackbody Curves

Here the slider is changing the temperature of the blackbody.
Notice that the y axis is set to scale based on the max intensity value for the current temp._____no_output_____

from ipywidgets import FloatSlider

def blackBody(T):
    kb = 1.380649*10**(-23) # J/K
    c = 299792458 # m/s
    h = 6.62607015*10**(-34) # Js

    l = np.arange(0.01,4,0.01)*10**(-6)
    B = np.zeros(len(l))

    for i in range(len(l)):
        B[i] = 2*h*c**2/l[i]**5 * 1/(np.exp(h*c/(l[i]*kb*T))-1)

    fig = plt.figure(num=3,figsize=(15,10))
    ax = plt.subplot(xlim=(0,3),ylim=(0,np.floor(max(B)/10**13+1)))
    ax.plot(l*10**6, B/10**13, c="gold")
    ax.set_xlabel("Wavelength / micrometer")
    ax.set_ylabel("Spectral Intensity / 10^13 W/sr/m^3")
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    plt.show()

interactive_plot = interactive(blackBody, T=FloatSlider(min=2500,max=10000,step=1,continuous_update=False))
interactive_plot_____no_output_____%load_ext watermark

# python, ipython, packages, and machine characteristics
%watermark -v -m -p numpy,matplotlib,IPython,watermark

# date
print (" ")
%watermark -u -n -t -z

The watermark extension is already loaded. To reload it, use:
  %reload_ext watermark
Python implementation: CPython
Python version       : 3.8.8
IPython version      : 7.22.0

numpy     : 1.20.1
matplotlib: 3.3.4
IPython   : 7.22.0
watermark : 2.2.0

Compiler    : MSC v.1916 64 bit (AMD64)
OS          : Windows
Release     : 10
Machine     : AMD64
Processor   : Intel64 Family 6 Model 140 Stepping 1, GenuineIntel
CPU cores   : 8
Architecture: 64bit

Last updated: Thu Sep 16 2021 10:12:00GMT Summer Time