Skip to content

Commit

Permalink
Automatically generate readable config file for documentation
Browse files Browse the repository at this point in the history
A new script converts the config_schema.yml file to a more readable version that mimics the structure of what a yml file input should look like, but includes argument descriptions, data types, defaults, requirements, and enumerations (if applicable). This file will be included in the documentation to help users write their own yml config files.
  • Loading branch information
aspeake committed Jan 2, 2024
1 parent 1254546 commit f28b2e6
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 38 deletions.
110 changes: 110 additions & 0 deletions docs/config_readable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
description: (string) A description of the scenario configuration.
Default None
ecm_prep:
add_typ_eff: (boolean) Enable additional typical efficiency.
Default False
adopt_scn_restrict: (string) Specify adoption scenario restrictions.
Allowable options are {'Technical potential', 'Max adoption
potential'}. Default None
alt_ref_carb: (boolean) Enable alternative reference carbon.
Default False
alt_regions: (string) Specify an alternative region breakdown.
Allowable options are {'EMM', 'AIA', 'State'}. Default None
captured_energy: (boolean) Enable captured energy calculation.
Default False
detail_brkout: (array) List of options by which to breakout
results. The `regions` options is only valid if the alt_regions
argument is set to `EMM`, and `fuel types` is only valid if
the split_fuel argument is set to False. Default []
exog_hp_rates:
exog_hp_rate_scenario: (string) Guidehouse E3HP conversion
scenario to use for exogenous HP rates. Allowable options
are {'conservative', 'optimistic', 'most aggressive', 'aggressive'}.
Default None
switch_all_retrofit_hp: (boolean) Assume all retrofits convert
to heat pumps, otherwise, retrofits are subject to the same
external heat pump conversion rates assumed for new/replacement
decisions. Only applicable if `exog_hp_rate_scenario` and
`retrofit_type` are defined. Default None
floor_start: (integer) The starting floor. Default 0
fugitive_emissions: (array) Array enabling fugitive emissions;
array may include methane and one of the two refrigerant options.
Default []
grid_decarb:
grid_assesment_timing: (string, required if the grid_decarb
key is present) When to assess avoided emissions and costs
from non-fuel switching measures relative to the additional
grid decarbonization. Allowable options are {'before', 'after'}.
Default None
grid_decarb_level: (string, required if the grid_decarb key
is present) Enable grid decarbonization - `0.8` represents
80%% reduced grid emissions from current levels by 2050,
and `full` represents full grid decarbonization by 2035.
Allowable options are {'0.8', 'full'}. Default None
health_costs: (boolean) Enable health costs. Default False
no_scnd_lgt: (boolean) Disable secondary lighting. Default False
pkg_env_costs: (string) Define what measure data should be written
out for inclusion in measure competition. `include HVAC` will
prepare HVAC-only versions of all HVAC/envelope packages for
measure competition, `exclude HVAC` will exclude these HVAC-only
measures from measure competition. Allowable options are {'include
HVAC', 'exclude HVAC'}. Default None
pkg_env_sep: (boolean) Enable package environmental separation.
Default False
retrofits:
retrofit_mult_year: (integer) The year by which the retorfit
multiplier is achieved (only for increasing retrofit_type).
Default None
retrofit_multiplier: (number) Factor by which early retrofit
rates are multiplied (only for increasing retrofit_type).
Default None
retrofit_type: (string, required if the retrofits key is present)
Type of retrofit. `constant` assumes component-based early
retrofit rates that do not change over time, `increasing`
assumes rates that increase over time. Allowable options
are {'constant', 'increasing'}. Default None
rp_persist: (boolean) Enable relative performance persistence.
Default False
sect_shapes: (boolean) Enable sector shapes. Default False
site_energy: (boolean) Enable site energy calculation. Default
False
split_fuel: (boolean) Enable split fuel. Default False
tsv_metrics:
tsv_average_days: (string) The day type to average over. Only
applicable if tsv_type is `energy` or tsv_power_agg is `average`.
Allowable options are {'weekends', 'weekdays', 'all'}. Default
None
tsv_daily_hr_restrict: (string, required if the tsv_metrics
key is present) The daily hour range to restrict time-sensitive
metrics, where `all` is all hours, `peak` is peak demand
period hours, and `low` is low demand period hours. Allowable
options are {'peak', 'low', 'all'}. Default None
tsv_energy_agg: (string) Define how the the tsv_daily_hr_restrict
hours are aggregated when tsv_type is `energy`. Allowable
options are {'sum', 'average'}. Default None
tsv_power_agg: (string) Define how the the tsv_daily_hr_restrict
hours are aggregated when tsv_type is `power`. Allowable
options are {'peak', 'average'}. Default None
tsv_season: (string) Season of focus for time-sensitve metrics.
Allowable options are {'winter', 'intermediate', 'summer'}.
Default None
tsv_sys_shape_case: (string) The basis for determining hours
for peak or low demand. Only applicable if tsv_daily_hr_restrict
is `peak` or `low`. Allowable options are {'total reference',
'total high renewables', 'net renewable high renewables',
'net renewable reference'}. Default None
tsv_type: (string, required if the tsv_metrics key is present)
Time-sensitive metric desired, where `energy` is the change
in energy and `power` is the change in power (e.g., single
hour GW). Allowable options are {'energy', 'power'}. Default
None
verbose: (boolean) Enable verbose mode. Default False
run:
mkt_fracs: (boolean) Flag market penetration outputs. Default
False
report_cfs: (boolean) Report competition adjustment fractions.
Default False
report_stk: (boolean) Report baseline/measure stock data. Default
False
trim_results: (boolean) Reduce results file size. Default False
verbose: (boolean) Print all warnings to stdout. Default False
42 changes: 42 additions & 0 deletions docs/generate_readable_cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from scout.config import Config
from scout.constants import FilePaths as fp
from pathlib import Path
import yaml

schema_file = fp.SUPPORTING_DATA / "config_schema.yml"
schema_data = Config._load_config(schema_file)
output_file = Path(__file__).resolve().parents[0] / "config_readable.yml"


def convert_yaml_structure(input_yaml, required=None, parent_key=None):
"""Translate schema file to more readable version for documentation"""
output_yaml = {}
for key, value in input_yaml.items():
if type(value) != dict:
continue
if value.get("type") == "object":
required = value.get("required", [])
output_yaml[key] = convert_yaml_structure(value["properties"], required, key)
elif type(value.get("description")) == str:
description = value["description"]
dtype = value["type"]
default = value.get("default")
enum = value.get("enum")
enum_txt = ""
if enum:
enum_txt = f" Allowable options are {set(enum)}."
req_txt = ""
if key in required:
req_txt = ", required"
if parent_key:
req_txt += f" if the {parent_key} key is present"

desc_str = f"({dtype}{req_txt}) {description}{enum_txt} Default {default}"
output_yaml[key] = desc_str

return output_yaml


output_cfg = convert_yaml_structure(schema_data["properties"], (schema_data["required"], None))
with open(output_file, "w") as file:
yaml.dump(output_cfg, file, default_flow_style=False, width=60)
7 changes: 4 additions & 3 deletions scout/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def __init__(self, parser, key, cli_args: list):
self.create_argparse(parser, schema_block)
self.set_config_args(self.cli_args)

def _load_config(self, filepath):
@classmethod
def _load_config(cls, filepath):
with open(filepath, "r") as file:
return yaml.safe_load(file)

Expand Down Expand Up @@ -108,7 +109,7 @@ def create_argparse(self, parser, schema_data, group=None):
arg_arr_choices = data.get("items", {}).get("enum")

if arg_type == "string" and arg_choices:
arg_help += f". Allowed values are {{{', '.join(arg_choices)}}}"
arg_help += f" Allowed values are {{{', '.join(arg_choices)}}}"
parser.add_argument(
f"--{arg_name}",
choices=arg_choices,
Expand All @@ -125,7 +126,7 @@ def create_argparse(self, parser, schema_data, group=None):
elif arg_type == "boolean":
parser.add_argument(f"--{arg_name}", action="store_true", help=arg_help)
elif arg_type == "array":
arg_help += f". Allowed values are 0 or more of {{{', '.join(arg_arr_choices)}}}"
arg_help += f" Allowed values are 0 or more of {{{', '.join(arg_arr_choices)}}}"
parser.add_argument(
f"--{arg_name}",
nargs="*",
Expand Down
Loading

0 comments on commit f28b2e6

Please sign in to comment.