Skip to content

Commit

Permalink
Merge pull request #71 from slevis-lmwg/mksurdat_iss36
Browse files Browse the repository at this point in the history
This merge includes the 
- jupyter notebook tool for generating SLIM surdat files (#71)
- python tool for modifying SLIM surdat files (#69)
  • Loading branch information
slevis-lmwg authored May 24, 2023
2 parents 0442448 + a13affd commit 3ccea41
Show file tree
Hide file tree
Showing 16 changed files with 2,216 additions and 0 deletions.
162 changes: 162 additions & 0 deletions python/slim/config_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
"""
General-purpose utilities and functions for handling command-line
config files in slim python codes.
"""

import logging
import configparser

from slim.utils import abort

logger = logging.getLogger(__name__)

# This string is used in the out-of-the-box slim.cfg and modify.cfg files
# to denote a value that needs to be filled in
_CONFIG_PLACEHOLDER = "FILL_THIS_IN"
# This string is used in the out-of-the-box slim.cfg and modify.cfg files
# to denote a value that can be filled in, but doesn't absolutely need to be
_CONFIG_UNSET = "UNSET"


def lon_range_0_to_360(lon_in):
"""
Description
-----------
Restrict longitude to 0 to 360 when given as -180 to 180.
"""
if -180 <= lon_in < 0:
lon_out = lon_in % 360
logger.info(
"Resetting longitude from %s to %s to keep in the range " " 0 to 360",
str(lon_in),
str(lon_out),
)
elif 0 <= lon_in <= 360 or lon_in is None:
lon_out = lon_in
else:
errmsg = "lon_in needs to be in the range 0 to 360"
abort(errmsg)

return lon_out


def get_config_value(
config,
section,
item,
file_path,
allowed_values=None,
default=None,
is_list=False,
convert_to_type=None,
can_be_unset=False,
):
"""Get a given item from a given section of the config object
Give a helpful error message if we can't find the given section or item
Note that the file_path argument is only used for the sake of the error message
If allowed_values is present, it should be a list of strings giving allowed values
The function _handle_config_value determines what to do if we read:
- a list or
- a str that needs to be converted to int / float / bool
- _CONFIG_UNSET: anything with the value "UNSET" will become "None"
"""
try:
val = config.get(section, item)
except configparser.NoSectionError:
abort("ERROR: Config file {} must contain section '{}'".format(file_path, section))
except configparser.NoOptionError:
abort(
"ERROR: Config file {} must contain item '{}' in section '{}'".format(
file_path, item, section
)
)

if val == _CONFIG_PLACEHOLDER:
abort("Error: {} needs to be specified in config file {}".format(item, file_path))

val = _handle_config_value(
var=val,
default=default,
item=item,
is_list=is_list,
convert_to_type=convert_to_type,
can_be_unset=can_be_unset,
allowed_values=allowed_values,
)
return val


def _handle_config_value(
var, default, item, is_list, convert_to_type, can_be_unset, allowed_values
):
"""
Description
-----------
Assign the default value or the user-specified one to var.
Convert from default type (str) to reqested type (int or float).
If is_list is True, then default should be a list
"""
if var == _CONFIG_UNSET:
if can_be_unset:
return default # default may be None
abort("Must set a value for .cfg file variable: {}".format(item))

# convert string to list of strings; if there is just one element,
# we will get a list of size one, which we will convert back to a
# scalar later if needed
var = var.split()

if convert_to_type is bool:
try:
var = [_convert_to_bool(v) for v in var]
except ValueError:
abort("Non-boolean value found for .cfg file variable: {}".format(item))
elif convert_to_type is not None:
try:
var = [convert_to_type(v) for v in var]
except ValueError:
abort("Wrong type for .cfg file variable: {}".format(item))

if allowed_values is not None:
for val in var:
if val not in allowed_values:
print("val = ", val, " in var not in allowed_values")
errmsg = (
"{} is not an allowed value for {} in .cfg file. "
"Check allowed_values".format(val, item)
)
abort(errmsg)

if not is_list:
if len(var) > 1:
abort("More than 1 element found for .cfg file variable: {}".format(item))
var = var[0]

return var


def _convert_to_bool(var):
"""
Function for converting different forms of
boolean strings to boolean value.
Args:
var (str): String bool input
Raises:
if the argument is not an acceptable boolean string
(such as yes or no ; true or false ; y or n ; t or f ; 0 or 1).
ValueError: The string should be one of the mentioned values.
Returns:
var_out (bool): Boolean value corresponding to the input.
"""
if var.lower() in ("yes", "true", "t", "y", "1", "on"):
var_out = True
elif var.lower() in ("no", "false", "f", "n", "0", "off"):
var_out = False
else:
raise ValueError("Boolean value expected. [true or false] or [y or n]")

return var_out
61 changes: 61 additions & 0 deletions python/slim/git_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""General-purpose git utility functions"""

import logging
import subprocess

from slim.path_utils import path_to_slim_root

logger = logging.getLogger(__name__)


def get_slim_git_short_hash():
"""
Returns Git short SHA for the SLIM repository.
Args:
Raises:
Returns:
sha (str) : git short hash for slim repository
"""
sha = (
subprocess.check_output(["git", "-C", path_to_slim_root(), "rev-parse", "--short", "HEAD"])
.strip()
.decode()
)
return sha


def get_slim_git_long_hash():
"""
Returns Git long SHA for the SLIM repository.
Args:
Raises:
Returns:
sha (str) : git long hash for slim repository
"""
sha = (
subprocess.check_output(["git", "-C", path_to_slim_root(), "rev-parse", "HEAD"])
.strip()
.decode()
)
return sha


def get_slim_git_describe():
"""
Function for giving the recent tag of the SLIM repository
Args:
Raises:
Returns:
label (str) : ouput of running 'git describe' for the SLIM repository
"""
label = subprocess.check_output(["git", "-C", path_to_slim_root(), "describe"]).strip().decode()
return label
Empty file.
Loading

0 comments on commit 3ccea41

Please sign in to comment.