Skip to content

Commit

Permalink
Merge branch 'add_abio' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
mnlevy1981 committed Oct 16, 2023
2 parents 951d1cd + e024578 commit 6e6b2f7
Show file tree
Hide file tree
Showing 50 changed files with 9,269 additions and 5,080 deletions.
19 changes: 17 additions & 2 deletions MARBL_tools/MARBL_diagnostics_file_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class MARBL_diagnostics_class(object):
# CONSTRUCTOR #
###############

def __init__(self, default_diagnostics_file, MARBL_settings):
def __init__(self, default_diagnostics_file, MARBL_settings, unit_system):
""" Class constructor: read the JSON file and then construct self.diagnostics_dict
"""

Expand Down Expand Up @@ -44,7 +44,7 @@ def __init__(self, default_diagnostics_file, MARBL_settings):
self.diagnostics_dict[diag_name] = dict(self._diagnostics[diag_name])
else:
# (Also determine correct frequency if 'frequency' is a dict)
self.diagnostics_dict.update(MARBL_tools.expand_template_value(diag_name, MARBL_settings, self._diagnostics[diag_name], check_freq=True))
self.diagnostics_dict.update(MARBL_tools.expand_template_value(diag_name, MARBL_settings, unit_system, self._diagnostics[diag_name], check_freq=True))

# ii. Delete diagnostics where dependencies are not met
# (Some diagnostics have already been removed via expand_template_value())
Expand All @@ -58,5 +58,20 @@ def __init__(self, default_diagnostics_file, MARBL_settings):
self.diagnostics_dict[diag_name]['frequency'] = [self.diagnostics_dict[diag_name]['frequency']]
self.diagnostics_dict[diag_name]['operator'] = [self.diagnostics_dict[diag_name]['operator']]

# iv. update units
fix_units = {}
if unit_system == 'cgs':
fix_units["mmol/m^3 cm"] = "nmol/cm^2"
fix_units["mmol/m^3"] = "nmol/cm^3"
fix_units["meq/m^3"] = "neq/cm^3"
else:
fix_units["mmol/m^3 cm"] = "mmol/m^2"
fix_units["nmol/cm^2"] = "mmol/m^2"
fix_units["g/cm"] = "kg/m"
fix_units["cm"] = "m"

for key, value in fix_units.items():
self.diagnostics_dict[diag_name]["units"] = str(self.diagnostics_dict[diag_name]["units"]).replace(key, value)

for diag_name in diags_to_delete:
del self.diagnostics_dict[diag_name]
13 changes: 10 additions & 3 deletions MARBL_tools/MARBL_generate_diagnostics_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
(default: None)
-o DIAGNOSTICS_FILE_OUT, --diagnostics_file_out DIAGNOSTICS_FILE_OUT
Name of file to be written (default: marbl.diags)
-u {cgs,mks}, --unit_system {cgs,mks}
Unit system for parameter values (default: cgs)
-a, --append Append to existing diagnostics file (default: False)
"""

#######################################
Expand Down Expand Up @@ -129,9 +131,14 @@ def _parse_args(marbl_root):
parser.add_argument('-o', '--diagnostics_file_out', action='store', dest='diagnostics_file_out', default='marbl.diags',
help='Name of file to be written')

# Command line argument to where to write the settings file being generated
parser.add_argument('-u', '--unit_system', action='store', dest='unit_system', default='cgs',
choices=['cgs', 'mks'], help='Unit system for parameter values')

# Append to existing diagnostics file?
parser.add_argument('-a', '--append', action='store_true', dest='append',
help='Append to existing diagnostics file')

return parser.parse_args()

#######################################
Expand All @@ -151,8 +158,8 @@ def _parse_args(marbl_root):

from MARBL_tools import MARBL_settings_class
from MARBL_tools import MARBL_diagnostics_class
DefaultSettings = MARBL_settings_class(args.default_settings_file, args.saved_state_vars_source, args.grid, args.settings_file_in)
MARBL_diagnostics = MARBL_diagnostics_class(args.default_diagnostics_file, DefaultSettings)
DefaultSettings = MARBL_settings_class(args.default_settings_file, args.saved_state_vars_source, args.grid, args.settings_file_in, args.unit_system)
MARBL_diagnostics = MARBL_diagnostics_class(args.default_diagnostics_file, DefaultSettings, args.unit_system)

# Write the diagnostic file
generate_diagnostics_file(MARBL_diagnostics, args.diagnostics_file_out, args.append)
15 changes: 11 additions & 4 deletions MARBL_tools/MARBL_generate_settings_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,19 @@ def generate_settings_file(MARBL_settings, settings_file_out):

fout = open(settings_file_out,"w")
# Sort variables by subcategory
written_any = False
for subcat_name in MARBL_settings.get_subcategory_names():
fout.write("! %s\n" % subcat_name.split('. ')[1])
header = "! %s\n" % subcat_name.split('. ')[1]
var_values = []
for varname in MARBL_settings.get_settings_dict_variable_names(subcat_name):
fout.write("%s = %s\n" % (varname, MARBL_settings.settings_dict[varname]['value']))
if subcat_name != MARBL_settings.get_subcategory_names()[-1]:
fout.write("\n")
var_values.append("%s = %s\n" % (varname, MARBL_settings.settings_dict[varname]['value']))
if len(var_values) > 0:
if written_any:
fout.write("\n")
written_any = True
fout.write(header)
for line in var_values:
fout.write(line)
fout.close()

#######################################
Expand Down
48 changes: 35 additions & 13 deletions MARBL_tools/MARBL_settings_file_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, default_settings_file, saved_state_vars_source="settings_file
# 5b. Need tracer count after determining PFT_derived_types, which means
# determining which tracers are active
if cat_name == "PFT_derived_types":
self.tracers_dict = self._get_tracers()
self.tracers_dict = self._get_tracers(unit_system)

# 6. Abort if not all values from input file were processed
# (That implies at least one variable from input file was not recognized)
Expand Down Expand Up @@ -180,7 +180,7 @@ def get_settings_dict_variable_names(self, subcategory):

################################################################################

def _get_tracers(self):
def _get_tracers(self, unit_system):
""" Parses self._settings['_tracer_list'] to determine what tracers
are enabled given other MARBL settings
"""
Expand All @@ -196,7 +196,7 @@ def _get_tracers(self):
if re.search('\(\(.*\)\)', tracer_name) == None:
tracer_dict[tracer_name] = dict(self._settings['_tracer_list'][tracer_name])
else:
tracer_dict.update(MARBL_tools.expand_template_value(tracer_name, self, self._settings['_tracer_list'][tracer_name]))
tracer_dict.update(MARBL_tools.expand_template_value(tracer_name, self, unit_system, self._settings['_tracer_list'][tracer_name]))

# 2. Delete tracers where dependencies are not met
# (Some tracers have already been removed via expand_template_value())
Expand All @@ -207,7 +207,10 @@ def _get_tracers(self):

# 3. Add tend_units and flux_units to dictionary
tracer_dict[tracer_name][u'tend_units'] = tracer_dict[tracer_name]['units'] + '/s'
tracer_dict[tracer_name][u'flux_units'] = tracer_dict[tracer_name]['units'] + ' cm/s'
if unit_system == 'cgs':
tracer_dict[tracer_name][u'flux_units'] = tracer_dict[tracer_name]['units'] + ' cm/s'
else:
tracer_dict[tracer_name][u'flux_units'] = tracer_dict[tracer_name]['units'] + ' m/s'

for tracer_name in tracers_to_delete:
del tracer_dict[tracer_name]
Expand Down Expand Up @@ -270,6 +273,12 @@ def _process_variable_value(self, category_name, variable_name, unit_system):
# Remove PFT-specific key
del self._config_keyword[-1]

# If array is length 0, remove it from settings dictionary
if len(_get_array_info(this_var["_array_shape"], self.settings_dict, self.tracers_dict)) == 0:
for key in self.get_category_names():
if variable_name in self._settings[key]:
del self._settings[key][variable_name]

################################################################################

def _update_settings_dict(self, this_var, var_name, unit_system, base_name=''):
Expand All @@ -282,6 +291,11 @@ def _update_settings_dict(self, this_var, var_name, unit_system, base_name=''):
(just varname for scalars, but multiple keys for arrays)
"""

# Return immediately if variable should not be in settings file
if 'dependencies' in this_var:
if this_var['dependencies'] not in self._config_keyword:
return

# Keys copied out of the settings file into settings_dict[varname]['attrs']
settings_dict_attrs = ['longname', 'units']

Expand Down Expand Up @@ -342,18 +356,21 @@ def _get_var_value(varname, var_dict, provided_keys, input_dict, units, unit_sys
# (Fortran vars are case-insensitive)
if varname.lower() in input_dict.keys():
# Ignore ' and " from strings
from_input_dict = True
def_value = input_dict[varname.lower()].strip('"').strip("'")
# Remove from input file dictionary; if dictionary is not empty after processing
# all input file lines, then it included a bad variable in it
del input_dict[varname.lower()]
# Note that if variable foo is an array, then foo = bar in the input file
# should be treated as foo(1) = bar
elif varname[-3:] == "(1)" and varname.lower()[:-3] in input_dict.keys():
from_input_dict = True
def_value = input_dict[varname.lower()[:-3]].strip('"').strip("'")
# Remove from input file dictionary; if dictionary is not empty after processing
# all input file lines, then it included a bad variable in it
del input_dict[varname.lower()[:-3]]
else:
from_input_dict = False
# is default value a dictionary? If so, it depends on self._config_keyword
# Otherwise we're interested in default value
if isinstance(var_dict["default_value"], dict):
Expand All @@ -378,7 +395,7 @@ def _get_var_value(varname, var_dict, provided_keys, input_dict, units, unit_sys
def_value = var_dict["default_value"]

# call translate value from JSON file to format F90 expects
value = _translate_JSON_value(def_value, var_dict["datatype"], units, unit_system)
value = _translate_JSON_value(def_value, var_dict["datatype"], units, unit_system, from_input_dict=from_input_dict)

# Append to config keywords if JSON wants it
if "_append_to_config_keywords" in var_dict.keys():
Expand All @@ -395,7 +412,7 @@ def _get_var_value(varname, var_dict, provided_keys, input_dict, units, unit_sys

################################################################################

def _translate_JSON_value(value, datatype, units, unit_system):
def _translate_JSON_value(value, datatype, units, unit_system, from_input_dict=False):
""" The value provided in the JSON file needs to be adjusted depending on the datatype
of the variable. Strings need to be wrapped in "", and numbers written in
scientific notation need to be formatted consistently.
Expand All @@ -414,9 +431,9 @@ def _translate_JSON_value(value, datatype, units, unit_system):
# if variable is a real but value is unicode evaluate it
if datatype == "real":
if isinstance(value, str):
return "%24.16e" % (eval(value)*_get_scale_factor(units, unit_system))
return "%24.16e" % (eval(value)*_get_scale_factor(units, unit_system, from_input_dict))
else:
return value*_get_scale_factor(units, unit_system)
return value*_get_scale_factor(units, unit_system, from_input_dict)
# if variable is an integer but value is unicode convert it
if datatype == "integer" and isinstance(value, str):
return int(value)
Expand All @@ -439,7 +456,10 @@ def _unit_conv_dict():
new_dict['cgs']['m^2/mg s/yr'] = {'new_units': 'cm^2/ng s/yr', 'scale_factor': 0.01}
return new_dict

def _get_scale_factor(units, unit_system):
def _get_scale_factor(units, unit_system, from_input_dict=False):
if from_input_dict:
# Do not apply scale factor to user-specified values
return 1.
try:
return _unit_conv_dict()[unit_system][units]['scale_factor']
except:
Expand Down Expand Up @@ -494,7 +514,7 @@ def _sort_with_specific_suffix_first(list_in, suffix=None, sort_key=lambda s: s.

################################################################################

def _get_value(val_in, settings_dict, tracers_dict, dict_prefix=''):
def _get_value(val_in, settings_dict, tracers_dict, dict_prefix='', return_zero_for_unfound=False):
""" Translate val_in (which may be a variable name) to an integer value
"""

Expand All @@ -520,6 +540,8 @@ def _get_value(val_in, settings_dict, tracers_dict, dict_prefix=''):
try:
val_out = settings_dict[val_in]['value']
except:
if return_zero_for_unfound:
return 0
logger.error('Unknown variable name in _get_value: %s' % val_in)
MARBL_tools.abort(1)
return val_out
Expand Down Expand Up @@ -551,13 +573,13 @@ def _get_array_info(array_size_in, settings_dict, tracers_dict, dict_prefix=''):
logger.error("_get_array_info() only supports 1D and 2D arrays")
MARBL_tools.abort(1)

for i in range(0, _get_value(array_size_in[0], settings_dict, tracers_dict, dict_prefix)):
for j in range(0, _get_value(array_size_in[1], settings_dict, tracers_dict, dict_prefix)):
for i in range(0, _get_value(array_size_in[0], settings_dict, tracers_dict, dict_prefix, return_zero_for_unfound=True)):
for j in range(0, _get_value(array_size_in[1], settings_dict, tracers_dict, dict_prefix, return_zero_for_unfound=True)):
str_index.append("(%d,%d)" % (i+1,j+1))
return str_index

# How many elements? May be an integer or an entry in self.settings_dict
for i in range(0, _get_value(array_size_in, settings_dict, tracers_dict, dict_prefix)):
for i in range(0, _get_value(array_size_in, settings_dict, tracers_dict, dict_prefix, return_zero_for_unfound=True)):
str_index.append("(%d)" % (i+1))
return str_index

Expand Down
Loading

0 comments on commit 6e6b2f7

Please sign in to comment.