Examples#

Reading (and parsing) the STASH sections in a namelist#

You can read and parse the STASH sections in a namelist file using the parse_namelist() function. This function takes the path to a namelist file and returns a list of class BaseSection.

The function will parse variable sections (that start with “namelist:umstash_streq”), domain and time profiles (“namelist:umstash_domain” and “namelist:umstash_time” respectively), use sections (“namelist:umstash_use”) and the model output streams sections (“namelist:nlstcall_pp”).

By identifying the different sections, the function with asign a class to each one:

` python 'umstash_use': UseProfile, 'umstash_time': TimeProfile, 'umstash_domain': DomainProfile, 'umstash_streq': Variable, 'nlstcall_pp': OutputStream, ` Here is an example of how to use the parse_namelist() function:

import stashmap
sections = stashmap.read_namelist("examples/rose-app.conf", print_summary=True)
Parsed 215 sections — DomainProfile: 8/26, OutputStream: 7/12, TimeProfile: 10/26, UseProfile: 8/14, Variable: 133/137

Human-readable version of variables and profiles#

stash codes (like “m01s01i004”) are not very informative. You can get a human-readable version of the variables with the function describe_variable(). This function takes a list (of class BaseSection) or a string (a single stash code) and returns the variable name.

Here is an example of how to use the describe_variable() function:

Using the stash code:

stashmap.describe_variable("m01s01i004")
'TEMPERATURE AFTER SW RAD INCREMENTS'

Using a list of sections obtained from a namelist:

sections = stashmap.read_namelist("examples/rose-app.conf", print_summary=True)

stashmap.describe_variable(sections)

variables = [s for s in sections if isinstance(s, stashmap.Variable)]

for v in variables[0:15]:
    print("isec=", v.record.get('isec'), "item=", v.record.get('item'), "->", v.record.get('description'))
Parsed 215 sections — DomainProfile: 8/26, OutputStream: 7/12, TimeProfile: 10/26, UseProfile: 8/14, Variable: 133/137
isec= 0 item= 2 -> U COMPNT OF WIND AFTER TIMESTEP
isec= 0 item= 2 -> U COMPNT OF WIND AFTER TIMESTEP
isec= 0 item= 3 -> V COMPNT OF WIND AFTER TIMESTEP
isec= 0 item= 3 -> V COMPNT OF WIND AFTER TIMESTEP
isec= 0 item= 4 -> THETA AFTER TIMESTEP
isec= 0 item= 4 -> THETA AFTER TIMESTEP
isec= 0 item= 10 -> SPECIFIC HUMIDITY AFTER TIMESTEP
isec= 0 item= 10 -> SPECIFIC HUMIDITY AFTER TIMESTEP
isec= 0 item= 12 -> QCF AFTER TIMESTEP
isec= 0 item= 12 -> QCF AFTER TIMESTEP
isec= 0 item= 24 -> SURFACE TEMPERATURE AFTER TIMESTEP
isec= 0 item= 24 -> SURFACE TEMPERATURE AFTER TIMESTEP
isec= 0 item= 25 -> BOUNDARY LAYER DEPTH AFTER TIMESTEP
isec= 0 item= 150 -> W COMPNT OF WIND AFTER TIMESTEP
isec= 0 item= 150 -> W COMPNT OF WIND AFTER TIMESTEP

In the same way, you can get a human-readable version of the time and domain profiles with describe_profiles():

For time profiles it will decode each element and construct a description based on the values of the different fields.

sections = stashmap.read_namelist("examples/rose-app.conf", print_summary=True)

stashmap.describe_profiles(sections)

time = [s for s in sections if isinstance(s, stashmap.TimeProfile)]

for t in time:
    print(t.record.get('tim_name'), "->", t.record.get('description'))
Parsed 215 sections — DomainProfile: 8/26, OutputStream: 7/12, TimeProfile: 10/26, UseProfile: 8/14, Variable: 133/137
T24H0Z -> Instantaneous every 24 hours, 
T3HACUM -> Accumulated every 3 hours, using data every 1 timestep, starting at 0 timestep, 
T3HINST -> Instantaneous every 3 hours, 
T3HMN -> Time mean every 3 hours, using data every 1 timestep, starting at 0 timestep, 
T6H -> Instantaneous every 6 hours, 
T6HDAYM -> Time mean every 1 day, using data every 6 hours, starting at 0 hours, 
T6HINST -> Instantaneous every 6 hours, 
T6HMONM -> Time mean every 30 days, using data every 6 hours, starting at 0 hours, 
T6HRMAX -> Maximum every 6 hours, 
T90DAY -> Instantaneous every 90 days, 
TALLTS -> Instantaneous every 1 timestep, 
TDAYACUM -> Accumulated every 1 day, using data every 1 timestep, starting at 0 timestep, 
TDAYM -> Time mean every 1 day, using data every 1 timestep, starting at 0 timestep, 
TDAYMAX -> Maximum every 1 day, 
TDAYMIN -> Minimum every 1 day, 
TMONMN00 -> Time mean every 30 days, using data every 24 hours, starting at 0 hours, 
TMONMN03 -> Time mean every 30 days, using data every 24 hours, starting at 3 hours, 
TMONMN06 -> Time mean every 30 days, using data every 24 hours, starting at 6 hours, 
TMONMN09 -> Time mean every 30 days, using data every 24 hours, starting at 9 hours, 
TMONMN12 -> Time mean every 30 days, using data every 24 hours, starting at 12 hours, 
TMONMN15 -> Time mean every 30 days, using data every 24 hours, starting at 15 hours, 
TMONMN18 -> Time mean every 30 days, using data every 24 hours, starting at 18 hours, 
TMONMN21 -> Time mean every 30 days, using data every 24 hours, starting at 21 hours, 
TMONMN -> Time mean every 30 days, using data every 1 timestep, starting at 0 timestep, 
TRADMONM -> Time mean every 30 days, using data every 1 hour, starting at 0 hour, 
TSTEPGI -> Instantaneous every 1 timestep, 

And the same for domain profiles:

sections = stashmap.read_namelist("examples/rose-app.conf", print_summary=True)

stashmap.describe_profiles(sections)

domain = [s for s in sections if isinstance(s, stashmap.DomainProfile)]

for d in domain:
    print(d.record.get('dom_name'), "->", d.record.get('description'))
Parsed 215 sections — DomainProfile: 8/26, OutputStream: 7/12, TimeProfile: 10/26, UseProfile: 8/14, Variable: 133/137
D1RH -> Global, Model rho levels: levels 1, 
D1TH -> Global, Model theta levels: levels 1, 
D52RH -> Global, Model rho levels: levels 1 to 52
D52TH -> Global, Model theta levels: levels 1 to 52
DALLRH -> Global, Model rho levels: levels 1 to 85
DALLTH -> Global, Model theta levels: levels 1 to 85
DCOSP40H -> Global, Geometric height levels, 
DCOSP7x7 -> Global, Pressure levels: 900.000,740.000,620.000,500.000,375.000,245.000,115.000, COSP pseudo level categories for satellite observation simulator project, 
DCOSPCFL -> Global, Geometric height levels, COSP pseudo level categories for satellite observation simulator project, 
DIAG -> Global, Single level, 
DIAGAOT -> Global, Single level, NA, 
DICECAT -> Global, Single level, Sea ice categories, 
DP34 -> Global, Pressure levels: 1000.000,975.000,950.000,925.000,900.000,875.000,850.000,825.000,800.000,775.000,750.000,700.000,650.000,600.000,550.000,500.000,450.000,400.000,350.000,300.000,250.000,225.000,200.000,175.000,150.000,125.000,100.000,70.000,50.000,30.000,20.000,10.000,5.000,1.000, 
DP500 -> Global, Pressure levels: 500.000, 
DP6 -> Global, Pressure levels: 925.000,850.000,700.000,500.000,300.000,200.000, 
DP7LOW -> Global, Pressure levels: 1000.000,925.000,850.000,700.000,600.000,500.000,400.000, 
DP850200 -> Global, Pressure levels: 850.000,200.000, 
DP855020 -> Global, Pressure levels: 850.000,500.000,200.000, 
DPBLTH -> Global, Model theta levels: levels 1 to 50
DPFTS -> Global, Single level, Land and Vegetation Surface Types, 
DPMONSTA -> Global, Pressure levels: 1000.000,925.000,850.000,700.000,600.000,500.000,400.000,300.000,250.000,200.000,170.000,150.000,130.000,115.000,100.000,90.000,80.000,70.000,50.000,30.000,20.000,15.000,10.000,7.000,5.000,3.000,2.000,1.500,1.000,0.700,0.500,0.300,0.200,0.150,0.100,0.070,0.050,0.030, 
DPMONSZ -> Global, Zonal average, Pressure levels: 1000.000,925.000,850.000,700.000,600.000,500.000,400.000,300.000,250.000,200.000,170.000,150.000,130.000,115.000,100.000,90.000,80.000,70.000,50.000,30.000,20.000,15.000,10.000,7.000,5.000,3.000,2.000,1.500,1.000,0.700,0.500,0.300,0.200,0.150,0.100,0.070,0.050,0.030, 
DSOIL -> Global, Deep soil levels: levels 1 to 6
DTH16 -> Global, Potential temperature levels, 
DTILE -> Global, Single level, Land and Vegetation Surface Types, 
DTROP -> Area specified in whole degrees: N=40, S=-40, W=0, E=360, Single level, 

It is recomended to use these functions after reading a namelist file with parse_namelist() to get a human-readable version of the variables and profiles defined in the namelist.

Exporting to csv fields#

On of the main reasons for this package to exist is to be able to read the namelist and save it into a csv file and work on the stash list, hopefully after you added the human-readable description for each one. The function export_sections_to_csv() takes the list of sections obtained from parse_namelist() and a path (without extension) to save the csv files. By default, it will create different 3 csv files for variables, time profiles and domain profiles. Optionally you can export only variables by setting section_type=’variables’.

stashmap.export_sections_to_csv(sections, "examples/stash")

For this example, it will create on file called stash_variables.csv.

Exporting to namelist#

Finally, it is possible to export back to namelist format.

The function write_namelist() takes a list of sections (of class BaseSection) or a path to a csv file with the necessary columns and creates a text file in namelist format. Then, you can copy the content of that file to the rose-app.conf.

stashmap.write_namelist(sections, "examples/new_stash.txt")

N = 10
with open("examples/new_stash.txt", "r") as file:
    for i in range(N):
        line = next(file).strip()
        print(line)
[namelist:nlstcall_pp(pp0)]
file_id='pp0'
!!filename=''
filename_base='$DATAM/${RUNID}a.pa%C'
l_reinit=.true.
packing=0
reinit_end=-1
reinit_start=0
reinit_step=30
reinit_unit=2

Note

Currently, if the input is a csv file, it will only export variable sections (umstash_streq).

stashmap.write_namelist("examples/stash_variables.csv", "examples/new_stash.txt")

N = 10
with open("examples/new_stash.txt", "r") as file:
    for i in range(N):
        line = next(file).strip()
        print(line)
[namelist:umstash_streq(00002_35ln8wph)]
dom_name='DALLTH'
isec=0
item=2
package='3D Standard Diagnostics'
tim_name='TMONMN'
use_name='UPG'

[namelist:umstash_streq(00002_g5zvpdc4)]
dom_name='DALLTH'