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'