"""Provides a command line interface to the ``otoole`` package
The key functions are **convert**, **cplex** and **viz**.
The ``convert`` command allows convertion of multiple different OSeMOSYS input formats
including from/to csv, an AMPL format datafile, a folder of
CSVs, an Excel workbook with one tab per parameter, an SQLite database
The ``cplex`` command provides access to scripts which transform and process a CPLEX
solution file into a format which is more readily processed - either to CBC or CSV
format.
The ``validate`` command checks the technology and fuel names
against a standard or user defined configuration file.
The **viz** command allows you to produce a Reference Energy System diagram
Example
-------
Ask for help on the command line::
>>> $ otoole --help
usage: otoole [-h] [--verbose] [--version] {convert,cplex,validate,viz} ...
otoole: Python toolkit of OSeMOSYS users
positional arguments:
{convert,cplex,validate,viz}
convert Convert from one input format to another
cplex Process a CPLEX solution file
validate Validate an OSeMOSYS model
viz Visualise the model
optional arguments:
-h, --help show this help message and exit
--verbose, -v Enable debug mode
--version, -V The version of otoole
"""
import argparse
import logging
import os
import shutil
import sys
from otoole import __version__, convert, convert_results, read
from otoole.exceptions import OtooleSetupError
from otoole.preprocess.setup import get_config_setup_data, get_csv_setup_data
from otoole.utils import read_packaged_file
from otoole.validate import main as validate
from otoole.visualise import create_res
from otoole.write_strategies import WriteCsv
logger = logging.getLogger(__name__)
[docs]def validate_model(args):
data_format = args.data_format
data_file = args.data_file
user_config = args.user_config
input_data, _ = read(user_config, data_format, data_file)
if args.validate_config:
validation_config = read_packaged_file(args.validate_config)
validate(input_data, validation_config)
else:
validate(input_data)
def _result_matrix(args):
"""Covert results"""
convert_results(
args.config,
args.from_format,
args.to_format,
args.from_path,
args.to_path,
args.input_format,
args.input_path,
write_defaults=args.write_defaults,
glpk_model=args.glpk_model,
)
def _conversion_matrix(args):
"""Convert from one format to another
Implemented conversion functions::
from\to ex cs df
--------------------
excel -- yy --
csv nn -- nn
datafile nn -- --
"""
convert(
args.config,
args.from_format,
args.to_format,
args.from_path,
args.to_path,
write_defaults=args.write_defaults,
keep_whitespace=args.keep_whitespace,
)
[docs]def data2res(args):
"""Get input data and call res creation."""
data_format = args.data_format
data_path = args.data_path
config = args.config
resfile = args.resfile
input_data, _ = read(config, data_format, data_path)
create_res(input_data, resfile)
[docs]def setup(args):
"""Creates template data"""
data_type = args.data_type
data_path = args.data_path
write_defaults = args.write_defaults
overwrite = args.overwrite
if os.path.exists(data_path) and not overwrite:
raise OtooleSetupError(resource=data_path)
if data_type == "config":
shutil.copyfile(
os.path.join(os.path.dirname(__file__), "preprocess", "config.yaml"),
data_path,
)
elif data_type == "csv":
config = get_config_setup_data()
input_data, default_values = get_csv_setup_data(config)
WriteCsv(user_config=config).write(
input_data, data_path, default_values, write_defaults=write_defaults
)
[docs]def get_parser():
parser = argparse.ArgumentParser(
description="otoole: Python toolkit of OSeMOSYS users"
)
parser.add_argument(
"--verbose", "-v", help="Enable debug mode", action="count", default=0
)
parser.add_argument(
"--version",
"-V",
action="version",
version=__version__,
help="The version of otoole",
)
subparsers = parser.add_subparsers()
# Parser for results
result_parser = subparsers.add_parser("results", help="Post-process solution files")
result_parser.add_argument(
"from_format",
help="Result data format to convert from",
choices=sorted(["cbc", "cplex", "gurobi", "glpk"]),
)
result_parser.add_argument(
"to_format",
help="Result data format to convert to",
choices=sorted(["csv"]),
)
result_parser.add_argument(
"from_path", help="Path to file or folder to convert from"
)
result_parser.add_argument("to_path", help="Path to file or folder to convert to")
result_parser.add_argument(
"input_format",
help="Input data format",
choices=sorted(["csv", "datafile", "excel"]),
)
result_parser.add_argument("input_path", help="Path to input_data")
result_parser.add_argument("config", help="Path to config YAML file")
result_parser.add_argument(
"--glpk_model",
help="GLPK model file required for processing GLPK results",
default=None,
)
result_parser.add_argument(
"--write_defaults",
help="Writes default values",
default=False,
action="store_true",
)
result_parser.set_defaults(func=_result_matrix)
# Parser for conversion
convert_parser = subparsers.add_parser(
"convert", help="Convert from one input format to another"
)
convert_parser.add_argument(
"from_format",
help="Input data format to convert from",
choices=sorted(["datafile", "excel", "csv"]),
)
convert_parser.add_argument(
"to_format",
help="Input data format to convert to",
choices=sorted(["datafile", "csv", "excel"]),
)
convert_parser.add_argument(
"from_path", help="Path to file or folder to convert from"
)
convert_parser.add_argument("to_path", help="Path to file or folder to convert to")
convert_parser.add_argument("config", help="Path to config YAML file")
convert_parser.add_argument(
"--write_defaults",
help="Writes default values",
default=False,
action="store_true",
)
convert_parser.add_argument(
"--keep_whitespace",
help="Keeps leading/trailing whitespace",
default=False,
action="store_true",
)
convert_parser.set_defaults(func=_conversion_matrix)
# Parser for validation
valid_parser = subparsers.add_parser("validate", help="Validate an OSeMOSYS model")
valid_parser.add_argument(
"data_format",
help="Input data format",
choices=sorted(["datafile", "excel", "csv"]),
)
valid_parser.add_argument(
"data_file", help="Path to the OSeMOSYS data file to validate"
)
valid_parser.add_argument("user_config", help="Path to config YAML file")
valid_parser.add_argument(
"--validate_config", help="Path to a user-defined validation-config file"
)
valid_parser.set_defaults(func=validate_model)
# Parser for visualisation
viz_parser = subparsers.add_parser("viz", help="Visualise the model")
viz_subparsers = viz_parser.add_subparsers()
res_parser = viz_subparsers.add_parser(
"res", help="Generate a reference energy system"
)
res_parser.add_argument(
"data_format",
help="Input data format",
choices=sorted(["datafile", "excel", "csv"]),
)
res_parser.add_argument("data_path", help="Input data path")
res_parser.add_argument("resfile", help="Path to reference energy system")
res_parser.add_argument("config", help="Path to config YAML file")
res_parser.set_defaults(func=data2res)
# parser for setup
setup_parser = subparsers.add_parser("setup", help="Setup template files")
setup_parser.add_argument(
"data_type", help="Type of file to setup", choices=sorted(["config", "csv"])
)
setup_parser.add_argument("data_path", help="Path to file or folder to save to")
setup_parser.add_argument(
"--write_defaults",
help="Writes default values",
default=False,
action="store_true",
)
setup_parser.add_argument(
"--overwrite",
help="Overwrites existing data",
default=False,
action="store_true",
)
setup_parser.set_defaults(func=setup)
return parser
[docs]class DeprecateAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
logger.warning(f"Argument {self.option_strings} is deprecated and is ignored.")
delattr(namespace, self.dest)
[docs]def main():
parser = get_parser()
args = parser.parse_args(sys.argv[1:])
if args.verbose >= 1 and args.verbose < 2:
logging.basicConfig(level=logging.INFO)
if args.verbose > 2:
logging.basicConfig(level=logging.DEBUG)
def exception_handler(
exception_type, exception, traceback, debug_hook=sys.excepthook
):
if args.verbose:
debug_hook(exception_type, exception, traceback)
else:
print("{}: {}".format(exception_type.__name__, str(exception)))
sys.excepthook = exception_handler
if "func" in args:
args.func(args)
else:
parser.print_help()