diff --git a/ush/generate_fire_emissions.py b/ush/generate_fire_emissions.py index 3714a9c37..8d71f5f6f 100755 --- a/ush/generate_fire_emissions.py +++ b/ush/generate_fire_emissions.py @@ -1,10 +1,8 @@ -######################################################################### -# # -# Python script for fire emissions preprocessing from RAVE FRP and FRE # -# (Li et al.,2022). # -# johana.romero-alvarez@noaa.gov # -# # -######################################################################### +""" +Python script for fire emissions preprocessing from RAVE FRP and FRE +(Li et al.,2022). +johana.romero-alvarez@noaa.gov +""" import sys import os import time @@ -13,14 +11,19 @@ import HWP_tools import interp_tools as i_tools -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Workflow -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def generate_emiss_workflow(staticdir, ravedir, newges_dir, predef_grid): + """ + Workflow + + staticdir: ??? + ravedir: ??? + newges_dir: ??? + predef_grid: ??? + """ # ---------------------------------------------------------------------- # Import envs from workflow and get the predifying grid - # Set variable names, constants and unit conversions + # Set variable names constants and unit conversions # Set predefined grid # Set directories # ---------------------------------------------------------------------- diff --git a/ush/interp_tools.py b/ush/interp_tools.py index cc9394786..5a9575d1c 100755 --- a/ush/interp_tools.py +++ b/ush/interp_tools.py @@ -1,3 +1,6 @@ +""" +Interpolation tools. +""" import datetime as dt import pandas as pd import os @@ -7,8 +10,13 @@ import numpy as np from netCDF4 import Dataset -#Create date range, this is later used to search for RAVE and HWP from previous 24 hours def date_range(current_day): + """ + Create date range, this is later used to search for RAVE and HWP from previous 24 hours. + + current_day: ??? + """ + print(f'Searching for interpolated RAVE for {current_day}') fcst_datetime = dt.datetime.strptime(current_day, "%Y%m%d%H") @@ -19,8 +27,15 @@ def date_range(current_day): print(f'Current cycle: {fcst_datetime}') return(fcst_dates) -# Check if interoplated RAVE is available for the previous 24 hours def check_for_intp_rave(intp_dir, fcst_dates, rave_to_intp): + """ + Check if interoplated RAVE is available for the previous 24 hours. + + intp_dir: ??? + fcst_dates: ??? + rave_to_intp: ??? + + """ intp_avail_hours = [] intp_non_avail_hours = [] # There are four situations here. @@ -48,8 +63,14 @@ def check_for_intp_rave(intp_dir, fcst_dates, rave_to_intp): return(intp_avail_hours, intp_non_avail_hours, inp_files_2use) -#Check if raw RAVE in intp_non_avail_hours list is available for interpolatation def check_for_raw_rave(RAVE, intp_non_avail_hours, intp_avail_hours): + """ + Check if raw RAVE in intp_non_avail_hours list is available for interpolatation. + + RAVE: ??? + intp_non_avail_hours: ??? + intp_avail_hours: ??? + """ rave_avail = [] rave_avail_hours = [] rave_nonavail_hours_test = [] @@ -72,8 +93,15 @@ def check_for_raw_rave(RAVE, intp_non_avail_hours, intp_avail_hours): print(f'FIRST DAY?: {first_day}') return(rave_avail, rave_avail_hours, rave_nonavail_hours_test, first_day) -#Create source and target fields def creates_st_fields(grid_in, grid_out, intp_dir, rave_avail_hours): + """ + Create source and target fields. + + grid_in: ??? + grid_out: ??? + intp_dir: ??? + rave_avail_hours: ??? + """ # Open datasets with context managers with xr.open_dataset(grid_in) as ds_in, xr.open_dataset(grid_out) as ds_out: @@ -91,9 +119,13 @@ def creates_st_fields(grid_in, grid_out, intp_dir, rave_avail_hours): print('Grid in and out files available. Generating target and source fields') return(srcfield, tgtfield, tgt_latt, tgt_lont, srcgrid, tgtgrid, src_latt, tgt_area) -#Define output and variable meta data def create_emiss_file(fout, cols, rows): - """Create necessary dimensions for the emission file.""" + """Create necessary dimensions for the emission file. + + fout: ??? + cols: ??? + rows: ??? + """ fout.createDimension('t', None) fout.createDimension('lat', cols) fout.createDimension('lon', rows) @@ -101,7 +133,17 @@ def create_emiss_file(fout, cols, rows): setattr(fout, 'TIME_RANGE', '1 hour') def Store_latlon_by_Level(fout, varname, var, long_name, units, dim, fval, sfactor): - """Store a 2D variable (latitude/longitude) in the file.""" + """Store a 2D variable (latitude/longitude) in the file. + + fout: ??? + varname: ??? + var: ??? + long_name: ??? + units: ??? + dim: ??? + fval: ??? + sfactor: ??? + """ var_out = fout.createVariable(varname, 'f4', ('lat','lon')) var_out.units=units var_out.long_name=long_name @@ -111,7 +153,16 @@ def Store_latlon_by_Level(fout, varname, var, long_name, units, dim, fval, sfact var_out.coordinates='geolat geolon' def Store_by_Level(fout, varname, long_name, units, dim, fval, sfactor): - """Store a 3D variable (time, latitude/longitude) in the file.""" + """Store a 3D variable (time, latitude/longitude) in the file. + + fout: ??? + varname: ??? + long_name: ??? + units: ??? + dim: ??? + fval: ??? + sfactor: ??? + """ var_out = fout.createVariable(varname, 'f4', ('t','lat','lon')) var_out.units=units var_out.long_name = long_name @@ -119,8 +170,18 @@ def Store_by_Level(fout, varname, long_name, units, dim, fval, sfactor): var_out.FillValue=fval var_out.coordinates='t geolat geolon' -#create a dummy rave interpolated file if first day or regrider fails def create_dummy(intp_dir, current_day, tgt_latt, tgt_lont, cols, rows): + """ + Create a dummy rave interpolated file if first day or regrider fails. + + intp_dir: ??? + current_day: ??? + tgt_latt: ??? + tgt_lont: ??? + cols: ??? + rows: ??? + + """ file_path = os.path.join(intp_dir, f'SMOKE_RRFS_data_{current_day}00.nc') dummy_file = np.zeros((cols, rows)) # Changed to 3D to match the '3D' dimensions with Dataset(file_path, 'w') as fout: @@ -143,8 +204,18 @@ def create_dummy(intp_dir, current_day, tgt_latt, tgt_lont, cols, rows): return "Emissions dummy file created successfully" -#generate regridder def generate_regrider(rave_avail_hours, srcfield, tgtfield, weightfile, inp_files_2use, intp_avail_hours): + """ + Generate regridder. + + rave_avail_hours: ??? + srcfield: ??? + tgtfield: ??? + weightfile: ??? + inp_files_2use: ??? + intp_avail_hours: ??? + """ + print('Checking conditions for generating regridder.') use_dummy_emiss = len(rave_avail_hours) == 0 and len(intp_avail_hours) == 0 regridder = None @@ -167,9 +238,27 @@ def generate_regrider(rave_avail_hours, srcfield, tgtfield, weightfile, inp_file return(regridder, use_dummy_emiss) -#process RAVE available for interpolation def interpolate_rave(RAVE, rave_avail, rave_avail_hours, use_dummy_emiss, vars_emis, regridder, srcgrid, tgtgrid, rave_to_intp, intp_dir, src_latt, tgt_latt, tgt_lont, cols, rows): + """ + Process RAVE available for interpolation. + + RAVE: ??? + rave_avail: ??? + rave_avail_hours: ??? + use_dummy_emiss: ??? + vars_emis: ??? + regridder: ??? + srcgrid: ??? + tgtgrid: ??? + rave_to_intp: ??? + intp_dir: ??? + src_latt: ??? + tgt_latt: ??? + tgt_lont: ??? + cols: ??? + rows: ??? + """ for index, current_hour in enumerate(rave_avail_hours): file_name = rave_avail[index] rave_file_path = os.path.join(RAVE, file_name[0]) @@ -221,4 +310,4 @@ def interpolate_rave(RAVE, rave_avail, rave_avail_hours, use_dummy_emiss, vars_e except (OSError, IOError, RuntimeError, FileNotFoundError, TypeError, IndexError, MemoryError) as e: print(f"Error reading NetCDF file {rave_file_path}: {e}") else: - print(f"File not found or dummy emissions required: {rave_file_path}") \ No newline at end of file + print(f"File not found or dummy emissions required: {rave_file_path}") diff --git a/ush/set_namelist.py b/ush/set_namelist.py index cd7f07ded..6b3ff338e 100755 --- a/ush/set_namelist.py +++ b/ush/set_namelist.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -''' +""" This utility updates a Fortran namelist file using the f90nml package. The settings that are modified are supplied via command line YAML-formatted string and/or YAML configuration files. @@ -64,7 +64,7 @@ - Given a user namelist and a base namelist, the script can dump the difference in the two to a YAML file that can be included as a section in the supported configs. -''' +""" import argparse import collections @@ -75,14 +75,12 @@ def config_exists(arg): - - ''' + """ Checks whether the config file exists and if it contains the input section. Returns the arg as provided if checks are passed. - ''' - # Agument is expected to be a 2-item list of file name and internal section - # name. + arg: a 2-item list of file name and internal section name. + """ file_name = arg[0] section_name = arg[1] @@ -102,8 +100,10 @@ def config_exists(arg): return [cfg, section_name] def file_exists(arg): + """ Check for existence of file - ''' Check for existence of file ''' + arg: ??? + """ if not os.path.exists(arg): msg = f'{arg} does not exist!' @@ -112,20 +112,22 @@ def file_exists(arg): return arg def load_config(arg): - - ''' + """ Check to ensure that the provided config file exists. If it does, load it with YAML's safe loader and return the resulting dict. - ''' + + arg: ??? + """ return yaml.safe_load(arg) def path_ok(arg): - - ''' + """ Check whether the path to the file exists, and is writeable. Return the path if it passes all checks, otherwise raise an error. - ''' + + arg: ??? + """ # Get the absolute path provided by arg dir_name = os.path.abspath(os.path.dirname(arg)) @@ -138,12 +140,11 @@ def path_ok(arg): raise argparse.ArgumentTypeError(msg) def parse_args(): - - ''' + """ Function maintains the arguments accepted by this script. Please see Python's argparse documenation for more information about settings of each argument. - ''' + """ parser = argparse.ArgumentParser( description='Update a Fortran namelist with user-defined settings.' @@ -195,11 +196,13 @@ def parse_args(): return parser.parse_args() def dict_diff(dict1, dict2): + """ + Produces a dictionary of how dict2 differs from dict1. - ''' - Produces a dictionary of how dict2 differs from dict1 - ''' - + dict1: ??? + dict2: ??? + + """ diffs = {} # Loop through dict1 sections and key/value pairs @@ -228,8 +231,10 @@ def dict_diff(dict1, dict2): return diffs def to_dict(odict): + """ Recursively convert OrderedDict to Python dict. - ''' Recursively convert OrderedDict to Python dict. ''' + odict: ??? + """ if not isinstance(odict, collections.OrderedDict): return odict @@ -241,27 +246,15 @@ def to_dict(odict): return ret def update_dict(dest, newdict, quiet=False): + """Overwrites all values in dest dictionary with values from newdict. Turn off + print statements with queit=True. The dest dict is updated in place. - ''' - Overwrites all values in dest dictionary with values from newdict. Turn off - print statements with queit=True. - - Input: - - dest A dict that is to be updated. - newdict A dict containing sections and keys corresponding to - those in dest and potentially additional ones, that will be used to - update the dest dict. - quiet An optional boolean flag to turn off output. - - Output: - - None - - Result: - - The dest dict is updated in place. - ''' + dest: A dict that is to be updated. + newdict: A dict containing sections and keys corresponding to + those in dest and potentially additional ones, that will be used + to update the dest dict. + quiet: An optional boolean flag to turn off output. + """ for sect, values in newdict: # If section is set to None, remove all contents from namelist @@ -286,7 +279,10 @@ def update_dict(dest, newdict, quiet=False): def main(cla): - ''' Using input command line arguments (cla), update a Fortran namelist file. ''' + """ Using input command line arguments (cla), update a Fortran namelist file. + + cla: command line arguments + """ # Load base namelist into dict nml = f90nml.Namelist()