2020-09-02 20:26:31 +00:00
# claude_top_level_library
import claude_low_level_library as low_level
import numpy as np
cimport numpy as np
cimport cython
ctypedef np . float64_t DTYPE_f
# laplacian of scalar field a
2020-09-09 20:00:57 +00:00
def laplacian_2D ( np . ndarray a , np . ndarray dx , DTYPE_f dy ) :
cdef np .ndarray output = np . zeros_like ( a )
cdef np .int_t nlat , nlon , i , j
cdef DTYPE_f inv_dx , inv_dy
nlat = a . shape [ 0 ]
nlon = a . shape [ 1 ]
inv_dy = 1 / dy
for i in np . arange ( 1 , nlat - 1 ) :
inv_dx = dx [ i ]
for j in range ( nlon ) :
output [ i , j ] = ( low_level . scalar_gradient_x_2D ( a , dx , nlon , i , j ) - low_level . scalar_gradient_x_2D ( a , dx , nlon , i , j ) ) * inv_dx + ( low_level . scalar_gradient_y_2D ( a , dy , nlat , i + 1 , j ) - low_level . scalar_gradient_y_2D ( a , dy , nlat , i - 1 , j ) ) * inv_dy
return output
def laplacian_3D ( np . ndarray a , np . ndarray dx , DTYPE_f dy , np . ndarray dz ) :
cdef np .ndarray output = np . zeros_like ( a )
cdef np .int_t nlat , nlon , nlevels , i , j , k
cdef DTYPE_f inv_dx , inv_dy
nlat = a . shape [ 0 ]
nlon = a . shape [ 1 ]
nlevels = a . shape [ 2 ]
inv_dy = 1 / dy
for i in np . arange ( 1 , nlat - 1 ) :
inv_dx = 1 / dx [ i ]
for j in range ( nlon ) :
for k in range ( nlevels - 1 ) :
output [ i , j , k ] = ( low_level . scalar_gradient_x ( a , dx , nlon , i , j , k ) - low_level . scalar_gradient_x ( a , dx , nlon , i , j , k ) ) * inv_dx + ( low_level . scalar_gradient_y ( a , dy , nlat , i + 1 , j , k ) - low_level . scalar_gradient_y ( a , dy , nlat , i - 1 , j , k ) ) * inv_dy + ( low_level . scalar_gradient_z ( a , dz , i , j , k + 1 ) - low_level . scalar_gradient_z ( a , dz , i , j , k - 1 ) ) / ( 2 * dz [ k ] )
return output
2020-09-02 20:26:31 +00:00
# divergence of (a*u) where a is a scalar field and u is the atmospheric velocity field
2020-09-09 20:00:57 +00:00
def divergence_with_scalar ( np . ndarray a , np . ndarray u , np . ndarray v , np . ndarray w , np . ndarray dx , DTYPE_f dy , np . ndarray dz ) :
cdef np .ndarray output = np . zeros_like ( a )
cdef np .ndarray au , av , aw
cdef np .int_t nlat , nlon , nlevels , i , j , k
nlat = output . shape [ 0 ]
nlon = output . shape [ 1 ]
nlevels = output . shape [ 2 ]
2020-09-02 20:26:31 +00:00
au = a * u
av = a * v
2020-09-09 20:00:57 +00:00
aw = a * w
2020-09-02 20:26:31 +00:00
for i in range ( nlat ) :
for j in range ( nlon ) :
for k in range ( nlevels ) :
2020-09-16 19:57:03 +00:00
output [ i , j , k ] = low_level . scalar_gradient_x ( au , dx , nlon , i , j , k ) + low_level . scalar_gradient_y ( av , dy , nlat , i , j , k ) + 1 * low_level . scalar_gradient_z ( aw , dz , i , j , k )
return output
# specifically thermal advection, converts temperature field to potential temperature field, then advects (adiabatically), then converts back to temperature
def thermal_advection ( np . ndarray temperature_atmos , np . ndarray air_pressure , np . ndarray u , np . ndarray v , np . ndarray w , np . ndarray dx , DTYPE_f dy , np . ndarray dz ) :
cdef np .ndarray output = np . zeros_like ( temperature_atmos )
cdef np .ndarray au , av , aw
cdef np .int_t nlat , nlon , nlevels , i , j , k
cdef np .ndarray theta = low_level . t_to_theta ( temperature_atmos , air_pressure )
nlat = output . shape [ 0 ]
nlon = output . shape [ 1 ]
nlevels = output . shape [ 2 ]
au = theta * u
av = theta * v
aw = theta * w
for i in range ( nlat ) :
for j in range ( nlon ) :
for k in range ( nlevels ) :
output [ i , j , k ] = low_level . scalar_gradient_x ( au , dx , nlon , i , j , k ) + low_level . scalar_gradient_y ( av , dy , nlat , i , j , k ) + 1 * low_level . scalar_gradient_z ( aw , dz , i , j , k )
output = low_level . theta_to_t ( output , air_pressure )
2020-09-02 20:26:31 +00:00
return output
def radiation_calculation ( np . ndarray temperature_world , np . ndarray temperature_atmos , np . ndarray air_pressure , np . ndarray air_density , np . ndarray heat_capacity_earth , np . ndarray albedo , DTYPE_f insolation , np . ndarray lat , np . ndarray lon , np . ndarray heights , np . ndarray dz , np . int_t t , np . int_t dt , DTYPE_f day , DTYPE_f year , DTYPE_f axial_tilt ) :
# calculate change in temperature of ground and atmosphere due to radiative imbalance
cdef np .int_t nlat , nlon , nlevels , i , j
cdef DTYPE_f fl = 0.1
cdef np .ndarray upward_radiation , downward_radiation , optical_depth , Q , pressure_profile , density_profile
2020-09-09 20:00:57 +00:00
cdef DTYPE_f sun_lat
2020-09-02 20:26:31 +00:00
nlat = temperature_atmos . shape [ 0 ]
nlon = temperature_atmos . shape [ 1 ]
nlevels = temperature_atmos . shape [ 2 ]
upward_radiation = np . zeros ( nlevels )
downward_radiation = np . zeros ( nlevels )
optical_depth = np . zeros ( nlevels )
Q = np . zeros ( nlevels )
for i in range ( nlat ) :
2020-09-09 20:00:57 +00:00
sun_lat = low_level . surface_optical_depth ( lat [ i ] )
2020-09-02 20:26:31 +00:00
for j in range ( nlon ) :
# calculate optical depth
pressure_profile = air_pressure [ i , j , : ]
density_profile = air_density [ i , j , : ]
2020-09-09 20:00:57 +00:00
optical_depth = sun_lat * ( fl * ( pressure_profile / pressure_profile [ 0 ] ) + ( 1 - fl ) * ( pressure_profile / pressure_profile [ 0 ] ) * * 4 )
2020-09-02 20:26:31 +00:00
# calculate upward longwave flux, bc is thermal radiation at surface
upward_radiation [ 0 ] = low_level . thermal_radiation ( temperature_world [ i , j ] )
for k in np . arange ( 1 , nlevels ) :
upward_radiation [ k ] = ( upward_radiation [ k - 1 ] - ( optical_depth [ k ] - optical_depth [ k - 1 ] ) * ( low_level . thermal_radiation ( temperature_atmos [ i , j , k ] ) ) ) / ( 1 + optical_depth [ k - 1 ] - optical_depth [ k ] )
# calculate downward longwave flux, bc is zero at TOA (in model)
downward_radiation [ - 1 ] = 0
for k in np . arange ( 0 , nlevels - 1 ) [ : : - 1 ] :
downward_radiation [ k ] = ( downward_radiation [ k + 1 ] - low_level . thermal_radiation ( temperature_atmos [ i , j , k ] ) * ( optical_depth [ k + 1 ] - optical_depth [ k ] ) ) / ( 1 + optical_depth [ k ] - optical_depth [ k + 1 ] )
# gradient of difference provides heating at each level
for k in np . arange ( nlevels ) :
2020-09-02 20:47:19 +00:00
Q [ k ] = - low_level . scalar_gradient_z_1D ( upward_radiation - downward_radiation , dz , k ) / ( 1E3 * density_profile [ k ] )
2020-09-02 20:26:31 +00:00
# make sure model does not have a higher top than 50km!!
# approximate SW heating of ozone
if heights [ k ] > 20E3 :
Q [ k ] + = low_level . solar ( 5 , lat [ i ] , lon [ j ] , t , day , year , axial_tilt ) * ( ( ( ( heights [ k ] - 20E3 ) / 1E3 ) * * 2 ) / ( 30 * * 2 ) ) / ( 24 * 60 * 60 )
temperature_atmos [ i , j , : ] + = Q * dt
# update surface temperature with shortwave radiation flux
temperature_world [ i , j ] + = dt * ( ( 1 - albedo [ i , j ] ) * ( low_level . solar ( insolation , lat [ i ] , lon [ j ] , t , day , year , axial_tilt ) + downward_radiation [ 0 ] ) - upward_radiation [ 0 ] ) / heat_capacity_earth [ i , j ]
return temperature_world , temperature_atmos
2020-09-09 20:00:57 +00:00
def velocity_calculation ( np . ndarray u , np . ndarray v , np . ndarray air_pressure , np . ndarray old_pressure , np . ndarray air_density , np . ndarray coriolis , DTYPE_f gravity , np . ndarray dx , DTYPE_f dy , DTYPE_f dt ) :
2020-09-02 20:26:31 +00:00
# introduce temporary arrays to update velocity in the atmosphere
2020-09-09 20:00:57 +00:00
cdef np .ndarray u_temp = np . zeros_like ( u )
cdef np .ndarray v_temp = np . zeros_like ( v )
cdef np .ndarray w_temp = np . zeros_like ( u )
2020-09-02 20:26:31 +00:00
2020-09-09 20:00:57 +00:00
cdef np .int_t nlat , nlon , nlevels , i , j , k
cdef DTYPE_f inv_density , inv_dt_grav
nlat = air_pressure . shape [ 0 ]
nlon = air_pressure . shape [ 1 ]
nlevels = air_pressure . shape [ 2 ]
inv_dt_grav = 1 / ( dt * gravity )
2020-09-02 20:26:31 +00:00
# calculate acceleration of atmosphere using primitive equations on beta-plane
2020-09-09 20:00:57 +00:00
for i in np . arange ( 3 , nlat - 3 ) . tolist ( ) :
2020-09-02 20:26:31 +00:00
for j in range ( nlon ) :
for k in range ( nlevels ) :
2020-09-09 20:00:57 +00:00
inv_density = 1 / air_density [ i , j , k ]
u_temp [ i , j , k ] + = dt * ( - u [ i , j , k ] * low_level . scalar_gradient_x ( u , dx , nlon , i , j , k ) - v [ i , j , k ] * low_level . scalar_gradient_y ( u , dy , nlat , i , j , k ) + coriolis [ i ] * v [ i , j , k ] - low_level . scalar_gradient_x ( air_pressure , dx , nlon , i , j , k ) * inv_density )
v_temp [ i , j , k ] + = dt * ( - u [ i , j , k ] * low_level . scalar_gradient_x ( v , dx , nlon , i , j , k ) - v [ i , j , k ] * low_level . scalar_gradient_y ( v , dy , nlat , i , j , k ) - coriolis [ i ] * u [ i , j , k ] - low_level . scalar_gradient_y ( air_pressure , dy , nlat , i , j , k ) * inv_density )
w_temp [ i , j , k ] + = - ( air_pressure [ i , j , k ] - old_pressure [ i , j , k ] ) * inv_density * inv_dt_grav
2020-09-02 20:26:31 +00:00
u + = u_temp
v + = v_temp
w = w_temp
# approximate friction
u * = 0.95
v * = 0.95
2020-09-09 20:00:57 +00:00
u [ : , : , 0 ] * = 0.8
v [ : , : , 0 ] * = 0.8
return u , v , w
2020-09-16 19:57:03 +00:00
def smoothing_3D ( np . ndarray a , DTYPE_f smooth_parameter , DTYPE_f vert_smooth_parameter = 0.5 ) :
cdef np .int_t nlat = a . shape [ 0 ]
cdef np .int_t nlon = a . shape [ 1 ]
cdef np .int_t nlevels = a . shape [ 2 ]
2020-09-09 20:00:57 +00:00
smooth_parameter * = 0.5
2020-09-16 19:57:03 +00:00
cdef np .ndarray test = np . fft . fftn ( a )
2020-09-09 20:00:57 +00:00
test [ int ( nlat * smooth_parameter ) : int ( nlat * ( 1 - smooth_parameter ) ) , : , : ] = 0
test [ : , int ( nlon * smooth_parameter ) : int ( nlon * ( 1 - smooth_parameter ) ) , : ] = 0
2020-09-16 19:57:03 +00:00
test [ : , : , int ( nlevels * vert_smooth_parameter ) : int ( nlevels * ( 1 - vert_smooth_parameter ) ) ] = 0
2020-09-09 20:00:57 +00:00
return np . fft . ifftn ( test ) . real