Commit fd559da1 authored by Woude, Auke van der's avatar Woude, Auke van der
Browse files

improved documentation

parent f7a938f2
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
""" """
Author : W. He Author : W. He
Adapted by Ingrid Super, last revisions 14-8-2018 Adapted by Ingrid Super, last revisions 14-8-2018
Adapted by Auke van der Woude, 09-2019 -- ...
Revision History: Revision History:
Basing on Wouter's codes, replace the TM5 model with the STILT model, April 2015. | -- Basing on Wouter's codes, replace the TM5 model with the STILT model, April 2015.
| -- Expanding code to include C14 and a biosphere module
This module holds specific functions needed to use the STILT model within the data assimilation shell. It uses the information This module holds specific functions needed to use the STILT model within the data assimilation shell. It uses the information
from the DA system in combination with the generic stilt.rc files. from the DA system in combination with the generic stilt.rc files.
...@@ -242,19 +243,6 @@ class STILTObservationOperator(ObservationOperator): ...@@ -242,19 +243,6 @@ class STILTObservationOperator(ObservationOperator):
while dumdate<(self.timefinishkey): # self.timefinishkey : dt while dumdate<(self.timefinishkey): # self.timefinishkey : dt
self.datelist.append(dumdate) self.datelist.append(dumdate)
dumdate=dumdate+dt dumdate=dumdate+dt
self.prepare_background(do_pseudo, self.timefinishkey)
def prepare_background(self, do_pseudo, datepoint):
background_concs = []
indices = self.get_time_indices(datepoint)
for species in self.spname:
filename = self.bgfile.strip('.nc') + '_' + species.lower() + '.nc'
bf = io.ct_read(filename, 'read')
background_conc = bf.get_variable('obs')[indices]
background_concs.append(background_conc)
background_concs = np.array(background_concs)
self.bg = background_concs
bf.close()
### !!!! Only cache if made dependent on datepoint/datetime !!!! ### !!!! Only cache if made dependent on datepoint/datetime !!!!
def get_time_index_nc(self, time=None): def get_time_index_nc(self, time=None):
...@@ -288,7 +276,12 @@ class STILTObservationOperator(ObservationOperator): ...@@ -288,7 +276,12 @@ class STILTObservationOperator(ObservationOperator):
"""Function that gets the footprint for the current time and site. """Function that gets the footprint for the current time and site.
Returns a 3D np.array with dims (time, lat, lon) Returns a 3D np.array with dims (time, lat, lon)
Input: Input:
site: str of 3 letter sitename. Is converted to uppercase. Example: 'hei'""" i_loc: number of location. Requires object to have a 'sitenames' property
datepoint: datetime of the footprint to be found.
Returns:
np.array (3d): Footprint with as indices time, lat, lon
"""
site = self.sitenames[i_loc].upper() site = self.sitenames[i_loc].upper()
path = self.model_settings['footdir'] + '/' + site.upper() + '24' path = self.model_settings['footdir'] + '/' + site.upper() + '24'
fname = path + '/footprint_{0}_{1}x{2:02d}x{3:02d}x{4:02d}*.nc'.format(site.upper(), fname = path + '/footprint_{0}_{1}x{2:02d}x{3:02d}x{4:02d}*.nc'.format(site.upper(),
...@@ -305,11 +298,17 @@ class STILTObservationOperator(ObservationOperator): ...@@ -305,11 +298,17 @@ class STILTObservationOperator(ObservationOperator):
@cached @cached
def get_background(self, i_species, i_loc, datepoint): def get_background(self, i_species, i_loc, datepoint):
"""Function that finds the center of mass of the first footprint and the time corresponding to it. """Function that finds the center of mass of the first footprint and the time corresponding to it.
and finds the concentration in the center of mass. This is used as the background.
Input: Input:
fp: 3d np.array of the footprint i_species: int: the index of the species for which the background should be found
time is taken from the observationoperator self.""" i_loc : int: the index of the locatin for which the background should be found
datepoint: datetime.datetime: the datetime of the background concentration
Returns:
float: background concentration
"""
from scipy import ndimage from scipy import ndimage
# First, get the footprint and find the first time of influence
foot = self.get_foot(i_loc, datepoint) foot = self.get_foot(i_loc, datepoint)
start_influence = -1 # In backtimes start_influence = -1 # In backtimes
total_influence = 0 total_influence = 0
...@@ -317,6 +316,7 @@ class STILTObservationOperator(ObservationOperator): ...@@ -317,6 +316,7 @@ class STILTObservationOperator(ObservationOperator):
start_influence += 1 start_influence += 1
total_influence = fp[start_influence].sum() total_influence = fp[start_influence].sum()
# Get the center of mass of the first influence
center_of_mass = ndimage.measurements.center_of_mass(fp[start_influence]) center_of_mass = ndimage.measurements.center_of_mass(fp[start_influence])
center_of_mass = np.array(np.rint(center_of_mass), dtype=int) center_of_mass = np.array(np.rint(center_of_mass), dtype=int)
...@@ -324,6 +324,7 @@ class STILTObservationOperator(ObservationOperator): ...@@ -324,6 +324,7 @@ class STILTObservationOperator(ObservationOperator):
index = self.get_time_index_nc() - (int(self.model_settings['num_backtimes']) - start_influence) index = self.get_time_index_nc() - (int(self.model_settings['num_backtimes']) - start_influence)
# Find the concentration at the center of mass at the correct time.
background_file = self.model_settings['bgfdir'] + '/background.nc' background_file = self.model_settings['bgfdir'] + '/background.nc'
background_map = nc.Dataset(background_file)[species_name] background_map = nc.Dataset(background_file)[species_name]
background_conc = background_map[index, center_of_mass[0], center_of_mass[1]] background_conc = background_map[index, center_of_mass[0], center_of_mass[1]]
...@@ -332,15 +333,32 @@ class STILTObservationOperator(ObservationOperator): ...@@ -332,15 +333,32 @@ class STILTObservationOperator(ObservationOperator):
@cached @cached
def get_background_orig(self, i_species, i_datepoint): def get_background_orig(self, i_species, i_datepoint):
"""Function that finds the background concentration, non-time dependent and hard-coded.
Input:
i_species: int: the index of the species for which the background should be found
i_loc : int: the index of the locatin for which the background should be found
datepoint: datetime.datetime: the datetime of the background concentration
Returns:
float: background concentration
"""
backgrounds = 406.15, 127.2 backgrounds = 406.15, 127.2
return backgrounds[i_species] return backgrounds[i_species]
@cached @cached
def get_c14_concentration(self, i_loc, i_datepoint, gpp, ter, ff_flux, background): def get_c14_concentration(self, i_loc, i_datepoint, gpp, ter, ff_flux, background):
"""Function that gets the c14 concentration based on the emissions by the biosphere and """Function that gets the c14 concentration based on the emissions by the biosphere,
emissions by nuclear plants. Based Ch4 of Deniza's thesis: Modeling $\Delta^{14}CO_2 for Western Europe fossil fuels and nuclear power. The constants are defined at the top of this script.
DobsCO2obs = Dbg(CO2bg + CO2p + CO2r) + DffCO2ff + Dn14CO2n""" Input:
i_loc: int: the index of the location for which the c14 concentration should be calculated
i_datepoint: int: the index of the datepoint for which the c14 should be calculated
gpp: float: The gross primary production in umol/s
ter: float: The total ecosystem respiration in umol/s
ff_flux: float: The fossil fuel flux in umol/s
background: float: The background CO2 concentration
Returns:
float: The C14 in ppm
float: Delta(14C) """
datepoint = self.datelist[i_datepoint] datepoint = self.datelist[i_datepoint]
# First, get the footprint # First, get the footprint
site = self.sitenames[i_loc] site = self.sitenames[i_loc]
...@@ -393,6 +411,12 @@ class STILTObservationOperator(ObservationOperator): ...@@ -393,6 +411,12 @@ class STILTObservationOperator(ObservationOperator):
@cached @cached
def get_nc_variable(self, file, fluxname): def get_nc_variable(self, file, fluxname):
"""Helper function that gets the values from an nc file
Input:
file: str: filename of the nc file of which the value should be taken
fluxname: str: name of the variable in the file
Returns:
np.ndarray: the values in the nc file"""
data = nc.Dataset(file, 'r') data = nc.Dataset(file, 'r')
fluxmap = data[fluxname][:] fluxmap = data[fluxname][:]
data.close() data.close()
...@@ -402,15 +426,19 @@ class STILTObservationOperator(ObservationOperator): ...@@ -402,15 +426,19 @@ class STILTObservationOperator(ObservationOperator):
def get_biosphere_concentration(self,i_loc, datepoint, total=False): def get_biosphere_concentration(self,i_loc, datepoint, total=False):
"""Function that calculates the atmospheric increase due to the exchange of fluxes over the footprint """Function that calculates the atmospheric increase due to the exchange of fluxes over the footprint
Input: Input:
site: str of 3 chars with the location. Example: 'hei' i_loc: int: index of the location for which the concentration should be calculated
tracer_info: dict with information on the tracer: datepoint: datetime.datetime: the datepoint for which the concentration should be calculated
path to fluxes, total: bool, optional: Whether to returned summed values or gpp and ter seperately as tuple
half-life, Returns:
recalculation factor""" if total == True:
float: The total biosphere flux in umol/s
else:
tuple of 2 floats: GPP and TER in umol/s """
# First, get the footprint # First, get the footprint
site = self.sitenames[i_loc] site = self.sitenames[i_loc]
foot = self.get_foot(i_loc, datepoint) foot = self.get_foot(i_loc, datepoint)
# Get the indices
indices = self.get_time_indices(datepoint) indices = self.get_time_indices(datepoint)
# Get the tracer fluxes # Get the tracer fluxes
file = self.model_settings['biosphere_fluxdir'] file = self.model_settings['biosphere_fluxdir']
...@@ -424,8 +452,14 @@ class STILTObservationOperator(ObservationOperator): ...@@ -424,8 +452,14 @@ class STILTObservationOperator(ObservationOperator):
else: return gpp_increase, ter_increase else: return gpp_increase, ter_increase
@cached @cached
def get_temporal_profiles(self, i_datepoint, i_station, i_member, do_pseudo=0): def get_temporal_profiles(self, i_datepoint, i_station, i_member):
""" Function that reads in the temporal profiles for the current timestep""" """ Function that reads in the temporal profiles for the current timestep
Input:
i_datepoint: int: the index of the datepoint for which the c14 should be calculated
i_station: int: the index of the location for which the c14 concentration should be calculated
i_member: int: the index of the member for which the simulation is run
Returns:
np.array (2): the time profiles for all categories. Indices: time, category"""
#read temporal profiles for the times within the footprint #read temporal profiles for the times within the footprint
time_indices = self.get_time_indices(self.datelist[i_datepoint]) time_indices = self.get_time_indices(self.datelist[i_datepoint])
station_name = self.sitenames[i_station] station_name = self.sitenames[i_station]
...@@ -442,6 +476,12 @@ class STILTObservationOperator(ObservationOperator): ...@@ -442,6 +476,12 @@ class STILTObservationOperator(ObservationOperator):
@cached @cached
def get_spatial_emissions(self, i_member, i_species): def get_spatial_emissions(self, i_member, i_species):
""" Function that gets the spatial emissions
Input:
i_member: int: the index of the member for which the simulation is run
i_species: int: the index of the species for which the simulation is run
Returns:
np.ndarray (3d): the spatial emissions per category, lat and lon"""
#read spatially distributed emissions calculated with the emission model #read spatially distributed emissions calculated with the emission model
emisfile = os.path.join(self.model_settings['datadir'],'prior_spatial_%03d.nc'%i_member) #format: species[SNAP,lon,lat] emisfile = os.path.join(self.model_settings['datadir'],'prior_spatial_%03d.nc'%i_member) #format: species[SNAP,lon,lat]
f = io.ct_read(emisfile,method='read') f = io.ct_read(emisfile,method='read')
...@@ -459,7 +499,7 @@ class STILTObservationOperator(ObservationOperator): ...@@ -459,7 +499,7 @@ class STILTObservationOperator(ObservationOperator):
i_species : int: index of the species i_species : int: index of the species
do_pseudo : bool: whether to do pseudo-observations or not do_pseudo : bool: whether to do pseudo-observations or not
Returns: Returns:
None""" float: the concentration increase at the respective location due to the emissions from the respective species"""
# get the date: # get the date:
datepoint = self.datelist[i_datepoint] datepoint = self.datelist[i_datepoint]
...@@ -493,9 +533,9 @@ class STILTObservationOperator(ObservationOperator): ...@@ -493,9 +533,9 @@ class STILTObservationOperator(ObservationOperator):
self.save_obs() self.save_obs()
def run(self,dacycle,do_pseudo): def run(self,dacycle,do_pseudo):
""" This function calls the OPS and STILT functions for each locations, species, ensemble member and time step""" """Function that loops over all members, locations, species and datepoints and calculates the concentration increase at that point (in time)
Adds the data as attribute to this object."""
#### do STILT
totser=np.array(int(self.dacycle['da.optimizer.nmembers'])*[(self.nrloc*self.nrspc*len(self.datelist))*[0.]]) totser=np.array(int(self.dacycle['da.optimizer.nmembers'])*[(self.nrloc*self.nrspc*len(self.datelist))*[0.]])
for i_member in range(int(self.dacycle['da.optimizer.nmembers'])): for i_member in range(int(self.dacycle['da.optimizer.nmembers'])):
conc_STILT=[] conc_STILT=[]
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment