Repository: OSeMOSYS/otoole

Issue:
Use otoole with custom OSeMOSYS parameters
If you modify the name of a parameter or set, or add a new parameter or set in an OSeMOSYS model which you wish to use with otoole, there is currently no way for the user to edit the `config.yaml` file.

Suggest:

- [x] adding `--config` flag to the command line
- [x] `setup` command to write the configuration to a file in a user directory
- [x] add documentation on how to add or remove parameters #113 #107
- [x] validate user config #133
Cannot convert model to Excel
When converting to Excel using otoole `v0.11.0` I get the following error:

```python
Traceback (most recent call last):
  File "/Users/wusher/miniconda3/envs/otoole38/bin/otoole", line 33, in <module>
    sys.exit(load_entry_point('otoole', 'console_scripts', 'otoole')())
  File "/Users/wusher/repository/otoole/src/otoole/cli.py", line 299, in main
    args.func(args)
  File "/Users/wusher/repository/otoole/src/otoole/cli.py", line 173, in conversion_matrix
    context.convert(args.from_path, args.to_path)
  File "/Users/wusher/repository/otoole/src/otoole/input.py", line 123, in convert
    self._write(inputs, output_filepath, default_values)
  File "/Users/wusher/repository/otoole/src/otoole/input.py", line 112, in _write
    self._write_strategy.write(inputs, filepath, default_values)
  File "/Users/wusher/repository/otoole/src/otoole/input.py", line 266, in write
    self._write_parameter(df, name, handle, default=default_value)
  File "/Users/wusher/repository/otoole/src/otoole/write_strategies.py", line 80, in _write_parameter
    df.to_excel(handle, sheet_name=name, merge_cells=False, index=True)
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/core/generic.py", line 2189, in to_excel
    formatter.write(
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/io/formats/excel.py", line 821, in write
    writer.write_cells(
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/io/excel/_openpyxl.py", line 410, in write_cells
    for cell in cells:
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/io/formats/excel.py", line 757, in get_formatted_cells
    for cell in itertools.chain(self._format_header(), self._format_body()):
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/io/formats/excel.py", line 576, in _format_header_regular
    coloffset = len(self.df.index[0])
  File "/Users/wusher/miniconda3/envs/otoole38/lib/python3.8/site-packages/pandas/core/indexes/multi.py", line 2028, in __getitem__
    if level_codes[key] == -1:
IndexError: index 0 is out of bounds for axis 0 with size 0
```

Discussion:

Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 007b09a..65bec4e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,12 +2,12 @@ exclude: '^docs/conf.py'
 
 repos:
 - repo: https://github.com/psf/black
-  rev: 21.5b1
+  rev: 22.6.0
   hooks:
     - id: black
-      language_version: python3.8
+      language_version: python3.9
 
-- repo: git://github.com/pre-commit/pre-commit-hooks
+- repo: https://github.com/pre-commit/pre-commit-hooks
   rev: v2.2.3
   hooks:
   - id: trailing-whitespace
@@ -26,11 +26,11 @@ repos:
     args: ['--max-line-length=88','--extend-ignore=E203']  # default of Black
 
 - repo: https://github.com/pre-commit/mirrors-isort
-  rev: v5.8.0
+  rev: v5.10.1
   hooks:
   - id: isort
 
 -   repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v0.812  # Use the sha / tag you want to point at
+    rev: v0.961  # Use the sha / tag you want to point at
     hooks:
     -   id: mypy
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index e138ca9..03276ad 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,10 @@
 =========
 Changelog
 =========
+Version 2.0
+===========
+- Requires explicit provision of a user-defined configuration file for otoole to workbook
+- Fixed issue #114 so that conversion to Excel workbooks is now operating
 
 Version 0.9
 ==========
diff --git a/README.rst b/README.rst
index 1f12372..1f33087 100644
--- a/README.rst
+++ b/README.rst
@@ -24,30 +24,29 @@ Description
 **otoole** is a Python package which provides a command-line interface
 for users of OSeMOSYS.
 
-The aim of the package is to provide a community resource which
-centralises the commonly used pre- and post-processing steps
-around the use of OSeMOSYS.
+The aim of the package is to provide commonly used pre- and post-processing steps
+for OSeMOSYS.
 
 .. image:: img/osemosys_dataflow.png
 
 **otoole** aims to support different ways of storing input data and results,
 including csv files, databases, datapackages and Excel workbooks,
 as well as different implementations of the OSeMOSYS model.
+This improves interoperability of analyses and
+generally makes life a little bit easier.
 
 Dependencies
 ------------
 
-*otoole* requires a number of dependencies, including pygraphviz,
-which can be difficult to install on Windows.
-
+*otoole* requires a number of dependencies.
 The easiest way to install the dependencies is to use miniconda.
 
 1. Obtain the `miniconda package: <https://docs.conda.io/en/latest/miniconda.html>`_
 2. Add the **conda-forge** channel ``conda config --add channels conda-forge``
 3. Create a new Python environment
-   ``conda create -n myenv python=3.7 networkx datapackage
+   ``conda create -n otoole python=3.7 networkx datapackage
    pandas graphviz=2.46.1 xlrd``
-4. Activate the new environment ``conda activate myenv``
+4. Activate the new environment ``conda activate otoole``
 5. Use pip to install otoole ``pip install otoole``
 
 
@@ -91,6 +90,10 @@ first need to install the package in *develop mode*::
     git checkout <branch you wish to use>
     python setup.py develop
 
+Alternatively, use pip to install otoole from git in editable mode
+
+    pip install -e git+http://github.com/OSeMOSYS/otoole@master#egg=otoole
+
 Now, all changes made in the codebase will automatically be reflected
 in the installed Python version accessible on the command line or from
 importing otoole modules into other Python packages.
diff --git a/docs/functionality.rst b/docs/functionality.rst
index b387711..c117325 100644
--- a/docs/functionality.rst
+++ b/docs/functionality.rst
@@ -18,8 +18,8 @@ Core Functionality
 .. image:: img/osemosys_dataflow.png
 
 As shown in the diagram, *otoole* deals primarily with data before and after OSeMOSYS.
-We call the data work upto the generation of a datafile which is read in by GLPK
-pre-processing.  Anything that happens with the immediate outputs of a solver, such as
+We call the data work prior to the generation of a datafile which is read in by GLPK
+pre-processing. Anything that happens with the immediate outputs of a solver, such as
 the recommended open-source solvers GLPK, CBC, or the proprietary solvers CPLEX and Gurobi,
 is called results and post-processing. You can find more information in the sections below.
 
@@ -50,49 +50,50 @@ complex transformations.
 This command allows you to convert between various different input formats::
 
     $ otoole convert --help
-
-    usage: otoole convert [-h]
-                        {csv,datafile,datapackage,excel,sql}
-                        {csv,datafile,datapackage,excel,sql} from_path to_path
+    usage: otoole convert [-h] {csv,datafile,datapackage,excel} {csv,datafile,datapackage,excel} from_path to_path config
 
     positional arguments:
-    {csv,datafile,datapackage,excel,sql}
+    {csv,datafile,datapackage,excel}
                             Input data format to convert from
-    {csv,datafile,datapackage,excel,sql}
+    {csv,datafile,datapackage,excel}
                             Input data format to convert to
     from_path             Path to file or folder to convert from
     to_path               Path to file or folder to convert to
+    config                Path to config YAML file
 
     optional arguments:
     -h, --help            show this help message and exit
 
+As of version 2.0, you must provide a user-defined configuration file containing information
+about all of the sets, parameters and result variables in your model. See more about this below.
+
 For example, to convert from an existing OSeMOSYS datafile, and create a Tabular Datapackage, you
 use the following command::
 
-    otoole convert datafile datapackage simplicity.txt simplicity
+    otoole convert datafile datapackage simplicity.txt simplicity config.yaml
 
 This creates the Tabular Datapackage in a folder called ``simplicity``.
 
 Similarly, create an Excel workbook from a datafile::
 
-    otoole convert datafile excel simplicity.txt simplicity.xlsx
+    otoole convert datafile excel simplicity.txt simplicity.xlsx config.yaml
 
 And then convert it back again::
 
-    otoole convert excel datafile simplicity.xlsx simplicity.txt
+    otoole convert excel datafile simplicity.xlsx simplicity.txt config.yaml
 
 To create a folder of CSV files from an Excel workbook::
 
-    otoole convert excel csv simplicity.xlsx simplicity
+    otoole convert excel csv simplicity.xlsx simplicity config.yaml
 
 To convert back again, run the following command::
 
-    otoole convert csv excel simplicity simplicity.xlsx
+    otoole convert csv excel simplicity simplicity.xlsx config.yaml
 
 In each of the examples, you provide the path to the file or folder, depending on the context.
 For a datapackage, you need to provide the path to the ``datapackage.json`` file::
 
-    otoole convert datapackage datafile simplicity/datapackage.json simplicity.txt
+    otoole convert datapackage datafile simplicity/datapackage.json simplicity.txt config.yaml
 
 The Excel workbook is created in a specific format. Each tab in the workbook corresponds to one set or parameter.
 Parameters with a ``YEAR`` index are pivotted, so that the elements in set ``YEAR`` create columns in a table, with
diff --git a/src/otoole/cli.py b/src/otoole/cli.py
index 3308232..e239805 100644
--- a/src/otoole/cli.py
+++ b/src/otoole/cli.py
@@ -87,9 +87,7 @@ def cplex2cbc(args):
 
 
 def result_matrix(args):
-    """Post-process results from CBC solution file into CSV format
-
-    """
+    """Post-process results from CBC solution file into CSV format"""
     msg = "Conversion from {} to {} is not yet implemented".format(
         args.from_format, args.to_format
     )
@@ -144,11 +142,10 @@ def conversion_matrix(args):
 
     config = None
     if args.config:
-        for filename in args.config:
-            _, ending = os.path.splitext(filename)
-            with open(filename, "r") as config_file:
-                config = _read_file(config_file, ending)
-            logger.info("Reading config from {}".format(filename))
+        _, ending = os.path.splitext(args.config)
+        with open(args.config, "r") as config_file:
+            config = _read_file(config_file, ending)
+        logger.info("Reading config from {}".format(args.config))
 
     if args.from_format == "datafile":
         read_strategy = ReadDatafile(user_config=config)
@@ -160,13 +157,13 @@ def conversion_matrix(args):
         read_strategy = ReadExcel(user_config=config)
 
     if args.to_format == "datapackage":
-        write_strategy = WriteDatapackage()
+        write_strategy = WriteDatapackage(user_config=config)
     elif args.to_format == "excel":
-        write_strategy = WriteExcel()
+        write_strategy = WriteExcel(user_config=config)
     elif args.to_format == "datafile":
-        write_strategy = WriteDatafile()
+        write_strategy = WriteDatafile(user_config=config)
     elif args.to_format == "csv":
-        write_strategy = WriteCsv()
+        write_strategy = WriteCsv(user_config=config)
 
     if read_strategy and write_strategy:
         context = Context(read_strategy, write_strategy)
@@ -205,7 +202,9 @@ def get_parser():
         choices=sorted(["cbc", "cplex", "gurobi"]),
     )
     result_parser.add_argument(
-        "to_format", help="Result data format to convert to", choices=sorted(["csv"]),
+        "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"
@@ -241,9 +240,7 @@ def get_parser():
         "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(
-        "-c", "--config", action="append", help="Path to config YAML files"
-    )
+    convert_parser.add_argument("config", help="Path to config YAML file")
     convert_parser.set_defaults(func=conversion_matrix)
 
     # Parser for validation
diff --git a/src/otoole/input.py b/src/otoole/input.py
index 2b34c99..992a981 100644
--- a/src/otoole/input.py
+++ b/src/otoole/input.py
@@ -1,6 +1,6 @@
 """The ``input`` module allows you to access the conversion routines programmatically
 
-To use the routines, you need to instanciate a ``ReadStrategy`` and a ``WriteStrategy``
+To use the routines, you need to instantiate a ``ReadStrategy`` and a ``WriteStrategy``
 relevant for the format of the input and output data.  You then pass these to a
 ``Context``.
 
@@ -41,12 +41,9 @@ Convert a GNUMathProg datafile to a folder of Tabular DataPackage::
 from __future__ import annotations
 
 import logging
-from abc import ABC, abstractmethod
-from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
-
 import pandas as pd
-
-from otoole.utils import read_packaged_file
+from abc import ABC, abstractmethod
+from typing import Any, Dict, Optional, TextIO, Tuple, Union
 
 logger = logging.getLogger(__name__)
 
@@ -101,8 +98,7 @@ class Context:
     def _read(
         self, filepath: str, **kwargs
     ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, Any]]:
-        """Delegate reading to the strategy, depending upon the format
-        """
+        """Delegate reading to the strategy, depending upon the format"""
         return self._read_strategy.read(filepath, **kwargs)
 
     def _write(self, inputs: Dict, filepath: str, default_values: Dict) -> None:
@@ -128,27 +124,23 @@ class Strategy(ABC):
 
     Arguments
     ---------
-    input_config : dict, default=None
+    user_config : dict, default=None
         A user configuration for the input parameters and sets
     results_config : dict, default=None
         A user configuration for the results parameters
 
     """
 
-    def __init__(
-        self, user_config: Optional[Dict] = None, results_config: Optional[Dict] = None
-    ):
-        self._input_config = {}  # type: Dict[str, Dict[str, Union[str, List[str]]]]
-        self._results_config = {}
+    def __init__(self, user_config: Dict[str, Dict]):
 
-        if user_config:
-            self.input_config = user_config
-        else:
-            self.input_config = self._read_config()
-        if results_config:
-            self._results_config = results_config
-        else:
-            self._results_config = self._read_results_config()
+        self.user_config = user_config
+
+        # self.input_config = {
+        #     x: y for x, y in self.user_config.items() if y["type"] in ["param", 'set']
+        # }
+        self.results_config = {
+            x: y for x, y in self.user_config.items() if y["type"] == "result"
+        }
 
     def _add_dtypes(self, config: Dict):
         for name, details in config.items():
@@ -162,23 +154,16 @@ class Strategy(ABC):
                 details["index_dtypes"] = dtypes
         return config
 
-    def _read_config(self) -> Dict[str, Dict]:
-        return read_packaged_file("config.yaml", "otoole.preprocess")
-
-    def _read_results_config(self) -> Dict[str, Dict]:
-        return read_packaged_file("config.yaml", "otoole.results")
-
     @property
-    def input_config(self) -> Dict:
-        return self._input_config
+    def user_config(self) -> Dict:
+        return self._user_config
 
-    @input_config.setter
-    def input_config(self, value: Dict):
-        self._input_config = self._add_dtypes(value)
-
-    @property
-    def results_config(self):
-        return self._results_config
+    @user_config.setter
+    def user_config(self, value: Dict):
+        if value:
+            self._user_config = self._add_dtypes(value)
+        elif value is None:
+            raise ValueError("A user configuration must be passed into the reader")
 
     @staticmethod
     def _read_default_values(config):
@@ -206,9 +191,9 @@ class WriteStrategy(Strategy):
 
     def __init__(
         self,
+        user_config: Dict,
         filepath: Optional[str] = None,
         default_values: Optional[Dict] = None,
-        user_config: Optional[Dict] = None,
     ):
         super().__init__(user_config=user_config)
         if filepath:
@@ -242,8 +227,7 @@ class WriteStrategy(Strategy):
         raise NotImplementedError()
 
     def write(self, inputs: Dict, filepath: str, default_values: Dict):
-        """Perform the conversion from dict of dataframes to destination format
-        """
+        """Perform the conversion from dict of dataframes to destination format"""
         self.filepath = filepath
         self.default_values = default_values
 
@@ -254,7 +238,7 @@ class WriteStrategy(Strategy):
             logger.debug("%s has %s columns: %s", name, len(df.index.names), df.columns)
 
             try:
-                entity_type = self.input_config[name]["type"]
+                entity_type = self.user_config[name]["type"]
             except KeyError:
                 try:
                     entity_type = self.results_config[name]["type"]
@@ -300,7 +284,7 @@ class ReadStrategy(Strategy):
         """
         for name, df in input_data.items():
 
-            details = self.input_config[name]
+            details = self.user_config[name]
 
             if details["type"] == "param":
                 logger.debug("Identified {} as a parameter".format(name))
diff --git a/src/otoole/read_strategies.py b/src/otoole/read_strategies.py
index 12eea6c..a3fe39e 100644
--- a/src/otoole/read_strategies.py
+++ b/src/otoole/read_strategies.py
@@ -1,11 +1,10 @@
 import logging
 import os
-from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
-
 import pandas as pd
 from amply import Amply
 from flatten_dict import flatten
 from pandas_datapackage_reader import read_datapackage
+from typing import Any, Dict, List, TextIO, Tuple, Union
 
 from otoole.input import ReadStrategy
 from otoole.preprocess.longify_data import check_datatypes, check_set_datatype
@@ -27,11 +26,10 @@ CSV_TO_EXCEL = {v: k for k, v in EXCEL_TO_CSV.items()}
 
 
 class ReadMemory(ReadStrategy):
-    """Read a dict of OSeMOSYS parameters from memory
-    """
+    """Read a dict of OSeMOSYS parameters from memory"""
 
     def __init__(
-        self, parameters: Dict[str, pd.DataFrame], user_config: Optional[Dict] = None
+        self, parameters: Dict[str, pd.DataFrame], user_config: Dict[str, Dict]
     ):
         super().__init__(user_config)
         self._parameters = parameters
@@ -40,7 +38,7 @@ class ReadMemory(ReadStrategy):
         self, filepath: Union[str, TextIO] = None, **kwargs
     ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, Any]]:
 
-        config = self.input_config
+        config = self.user_config
         default_values = self._read_default_values(config)
         self._parameters = self._check_index(self._parameters)
         return self._parameters, default_values
@@ -101,14 +99,13 @@ class _ReadTabular(ReadStrategy):
 
 
 class ReadExcel(_ReadTabular):
-    """Read in an Excel spreadsheet in wide format to a dict of Pandas DataFrames
-    """
+    """Read in an Excel spreadsheet in wide format to a dict of Pandas DataFrames"""
 
     def read(
         self, filepath: Union[str, TextIO], **kwargs
     ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, Any]]:
 
-        config = self.input_config
+        config = self.user_config
         default_values = self._read_default_values(config)
 
         xl = pd.ExcelFile(filepath, engine="openpyxl")
@@ -149,11 +146,11 @@ class ReadCsv(_ReadTabular):
 
         input_data = {}
 
-        default_values = self._read_default_values(self.input_config)
+        default_values = self._read_default_values(self.user_config)
 
-        for parameter, details in self.input_config.items():
+        for parameter, details in self.user_config.items():
             logger.info("Looking for %s", parameter)
-            config_details = self.input_config[parameter]
+            config_details = self.user_config[parameter]
 
             csv_path = os.path.join(filepath, parameter + ".csv")
 
@@ -165,13 +162,13 @@ class ReadCsv(_ReadTabular):
                 default_columns = expected_columns + ["VALUE"]
                 df = pd.DataFrame(columns=default_columns)
 
-            entity_type = self.input_config[parameter]["type"]
+            entity_type = self.user_config[parameter]["type"]
 
             if entity_type == "param":
                 narrow = self._check_parameter(df, config_details["indices"], parameter)
                 if not narrow.empty:
                     narrow_checked = check_datatypes(
-                        narrow, self.input_config, parameter
+                        narrow, self.user_config, parameter
                     )
                 else:
                     narrow_checked = narrow
@@ -179,7 +176,7 @@ class ReadCsv(_ReadTabular):
                 narrow = self._check_set(df, config_details, parameter)
                 if not narrow.empty:
                     narrow_checked = check_set_datatype(
-                        narrow, self.input_config, parameter
+                        narrow, self.user_config, parameter
                     )
                 else:
                     narrow_checked = narrow
@@ -198,9 +195,7 @@ class ReadDatapackage(ReadStrategy):
         inputs = read_datapackage(filepath)
         default_resource = inputs.pop("default_values").set_index("name").to_dict()
         default_values = default_resource["default_value"]
-        self.input_config = read_datapackage_schema_into_config(
-            filepath, default_values
-        )
+        self.user_config = read_datapackage_schema_into_config(filepath, default_values)
         inputs = self._check_index(inputs)
         return inputs, default_values
 
@@ -210,7 +205,7 @@ class ReadDatafile(ReadStrategy):
         self, filepath, **kwargs
     ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, Any]]:
 
-        config = self.input_config
+        config = self.user_config
         default_values = self._read_default_values(config)
         amply_datafile = self.read_in_datafile(filepath, config)
         inputs = self._convert_amply_to_dataframe(amply_datafile, config)
diff --git a/src/otoole/results/results.py b/src/otoole/results/results.py
index 1e8054c..9d4f1b3 100644
--- a/src/otoole/results/results.py
+++ b/src/otoole/results/results.py
@@ -104,7 +104,7 @@ class ReadResultsCBC(ReadResults):
                                     1  SIMPLICITY  2016  183.30788}
         """
 
-        sets = {x: y for x, y in self.input_config.items() if y["type"] == "set"}
+        sets = {x: y for x, y in self.user_config.items() if y["type"] == "set"}
 
         results = {}  # type: Dict[str, pd.DataFrame]
         not_found = []
@@ -115,7 +115,7 @@ class ReadResultsCBC(ReadResults):
             if not df.empty:
 
                 LOGGER.debug("Extracting results for %s", name)
-                indices = details["indices"]
+                indices = details["indices"]  # typing: List
 
                 df[indices] = df["Index"].str.split(",", expand=True)
 
@@ -255,7 +255,7 @@ class ReadCplex(ReadResults):
             raise NotImplementedError(ex)
         df = df.melt(var_name="YEAR", value_name="VALUE", ignore_index=False)
         df = df.reset_index()
-        df = check_datatypes(df, {**self.input_config, **self.results_config}, variable)
+        df = check_datatypes(df, self.user_config, variable)
         df = df.set_index(index)
         df = df[(df != 0).any(axis=1)]
         return df
@@ -279,7 +279,7 @@ class ReadGurobi(ReadResultsCBC):
             skiprows=2,
         )  # type: pd.DataFrame
         df[["Variable", "Index"]] = df["Variable"].str.split("(", expand=True)
-        df["Index"] = df["Index"].str.replace(")", "")
+        df["Index"] = df["Index"].str.replace(")", "", regex=True)
         LOGGER.debug(df)
         df = df[(df["Value"] != 0)].reset_index()
         return df[["Variable", "Index", "Value"]].astype({"Value": float})
@@ -316,10 +316,10 @@ class ReadCbc(ReadResultsCBC):
         df["Variable"] = (
             df["Variable"]
             .astype(str)
-            .str.replace(r"^\*\*", "")
+            .str.replace(r"^\*\*", "", regex=True)
             .str.split(expand=True)[1]
         )
         df[["Index", "Value"]] = df["indexvalue"].str.split(expand=True).loc[:, 0:1]
-        df["Index"] = df["Index"].str.replace(")", "")
+        df["Index"] = df["Index"].str.replace(")", "", regex=True)
         df = df.drop(columns=["indexvalue"])
         return df[["Variable", "Index", "Value"]].astype({"Value": float})
diff --git a/src/otoole/write_strategies.py b/src/otoole/write_strategies.py
index 79bdb17..79afd8d 100644
--- a/src/otoole/write_strategies.py
+++ b/src/otoole/write_strategies.py
@@ -77,14 +77,18 @@ class WriteExcel(WriteStrategy):
         except KeyError:
             name = parameter_name
         df = self._form_parameter(df, parameter_name, default)
-        df.to_excel(handle, sheet_name=name, merge_cells=False, index=True)
+        if not df.empty:
+            df.to_excel(handle, sheet_name=name, merge_cells=False, index=True)
+        else:
+            # df.to_excel(handle, sheet_name=name, merge_cells=False, index=False)
+            logger.info(f"Skipped writing {parameter_name} as it is empty")
 
     def _write_set(self, df: pd.DataFrame, set_name, handle: pd.ExcelWriter):
-        df = df.reset_index()
         df.to_excel(handle, sheet_name=set_name, merge_cells=False, index=False)
 
     def _footer(self, handle=pd.ExcelWriter):
-        handle.close()
+        # handle.close()
+        pass
 
 
 class WriteDatafile(WriteStrategy):
@@ -223,6 +227,6 @@ class WriteDatapackage(WriteCsv):
         with open(default_values_path, "w", newline="") as csv_file:
             csv_file.write("name,default_value\n")
 
-            for name, contents in self.input_config.items():
+            for name, contents in self.user_config.items():
                 if contents["type"] == "param":
                     csv_file.write("{},{}\n".format(name, contents["default"]))
diff --git a/src/otoole/preprocess/config.yaml b/tests/fixtures/config.yaml
similarity index 59%
rename from src/otoole/preprocess/config.yaml
rename to tests/fixtures/config.yaml
index 4ba8cd3..1a0e92e 100644
--- a/src/otoole/preprocess/config.yaml
+++ b/tests/fixtures/config.yaml
@@ -296,3 +296,177 @@ YearSplit:
     type: param
     dtype: float
     default: 0
+AnnualEmissions:
+    indices: [REGION,EMISSION,YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+AccumulatedNewCapacity:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+AnnualFixedOperatingCost:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+AnnualTechnologyEmission:
+    indices: [REGION, TECHNOLOGY, EMISSION, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+AnnualTechnologyEmissionByMode:
+    indices: [REGION, TECHNOLOGY, EMISSION, MODE_OF_OPERATION, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+AnnualVariableOperatingCost:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+CapitalInvestment:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+Demand:
+    indices: [REGION, TIMESLICE, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+DiscountedSalvageValue:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+DiscountedTechnologyEmissionsPenalty:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+NewCapacity:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+NewStorageCapacity:
+    indices: [REGION, STORAGE, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+NumberOfNewTechnologyUnits:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+ProductionByTechnology:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+ProductionByTechnologyAnnual:
+    indices: [REGION, TECHNOLOGY, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+RateOfActivity:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+RateOfProductionByTechnology:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+RateOfProductionByTechnologyByMode:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+RateOfUseByTechnology:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+RateOfUseByTechnologyByMode:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+SalvageValue:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+SalvageValueStorage:
+    indices: [REGION, STORAGE, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+TotalAnnualTechnologyActivityByMode:
+    indices: [REGION, TECHNOLOGY, MODE_OF_OPERATION, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+TotalCapacityAnnual:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+TotalDiscountedCost:
+    indices: [REGION,YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+TotalTechnologyAnnualActivity:
+    indices: [REGION, TECHNOLOGY, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+TotalTechnologyModelPeriodActivity:
+    indices: [REGION, TECHNOLOGY]
+    type: result
+    dtype: float
+    default: 0
+    calculated: True
+Trade:
+    indices: [REGION, REGION, TIMESLICE, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
+UseByTechnology:
+    indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
+    type: result
+    dtype: float
+    default: 0
+    calculated: False
diff --git a/src/otoole/results/config.yaml b/tests/fixtures/config_r.yaml
similarity index 88%
rename from src/otoole/results/config.yaml
rename to tests/fixtures/config_r.yaml
index c4ba2f8..fb0be65 100644
--- a/src/otoole/results/config.yaml
+++ b/tests/fixtures/config_r.yaml
@@ -1,174 +1,174 @@
 AnnualEmissions:
     indices: [REGION,EMISSION,YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 AccumulatedNewCapacity:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 AnnualFixedOperatingCost:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 AnnualTechnologyEmission:
     indices: [REGION, TECHNOLOGY, EMISSION, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 AnnualTechnologyEmissionByMode:
     indices: [REGION, TECHNOLOGY, EMISSION, MODE_OF_OPERATION, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 AnnualVariableOperatingCost:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 CapitalInvestment:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 Demand:
     indices: [REGION, TIMESLICE, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 DiscountedSalvageValue:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 DiscountedTechnologyEmissionsPenalty:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 NewCapacity:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 NewStorageCapacity:
     indices: [REGION, STORAGE, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 NumberOfNewTechnologyUnits:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 ProductionByTechnology:
     indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 ProductionByTechnologyAnnual:
     indices: [REGION, TECHNOLOGY, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 RateOfActivity:
     indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 RateOfProductionByTechnology:
     indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 RateOfProductionByTechnologyByMode:
     indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 RateOfUseByTechnology:
     indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 RateOfUseByTechnologyByMode:
     indices: [REGION, TIMESLICE, TECHNOLOGY, MODE_OF_OPERATION, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 SalvageValue:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 SalvageValueStorage:
     indices: [REGION, STORAGE, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 TotalAnnualTechnologyActivityByMode:
     indices: [REGION, TECHNOLOGY, MODE_OF_OPERATION, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 TotalCapacityAnnual:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 TotalDiscountedCost:
     indices: [REGION,YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 TotalTechnologyAnnualActivity:
     indices: [REGION, TECHNOLOGY, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 TotalTechnologyModelPeriodActivity:
     indices: [REGION, TECHNOLOGY]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: True
 Trade:
     indices: [REGION, REGION, TIMESLICE, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False
 UseByTechnology:
     indices: [REGION, TIMESLICE, TECHNOLOGY, FUEL, YEAR]
-    type: param
+    type: result
     dtype: float
     default: 0
     calculated: False


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 042a671..25c1a8d 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -9,7 +9,35 @@
 
 from pytest import fixture
 
+import os
 import pandas as pd
+from typing import Dict
+
+from otoole.utils import _read_file
+
+
+@fixture
+def user_config() -> Dict:
+    """Reads in an example user config
+
+    Read in an example user config file which can be passed into all
+    Read and Write strategies for testing
+
+    Returns
+    -------
+    Dict
+    """
+    file_path = os.path.join("tests", "fixtures", "config.yaml")
+    with open(file_path, "r") as config_file:
+        config = _read_file(config_file, ".yaml")  # typing: Dict
+
+    file_path = os.path.join("tests", "fixtures", "config_r.yaml")
+    with open(file_path, "r") as config_file:
+        results = _read_file(config_file, ".yaml")  # typing: Dict
+
+    config.update(results)
+
+    return config
 
 
 @fixture
diff --git a/tests/fixtures/simplicity.txt b/tests/fixtures/simplicity.txt
new file mode 100644
index 0000000..639cd2f
--- /dev/null
+++ b/tests/fixtures/simplicity.txt
@@ -0,0 +1,579 @@
+###############
+#    Sets     #
+###############
+#
+set DAYTYPE := 1 ;
+set FUEL := BAGASSE BIOMASS DSL ETH FEL1 FEL2 FER GAS HEAT LAND LANDFOREST LNDSUGCAN MOLASSES RAWSUG RIVERWATER SEC_EL STOREDENERGY SUGCAN WATAGR WATIN WATOUT ;
+set MODE_OF_OPERATION := 1 2 ;
+set SEASON := 1 2 3 ;
+set DAILYTIMEBRACKET := 1 2 ;
+set EMISSION := CO2 WATCON ;
+set REGION := SIMPLICITY ;
+set YEAR := 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 ;
+set STORAGE := DAM ;
+set TIMESLICE := ID IN SD SN WD WN ;
+set TECHNOLOGY := BACKSTOP1 BACKSTOP2 BIOMASSPRO CHP ETHPLANT ELEC_IMPORT GAS_EXTRACTION GAS_IMPORT GRID_EXP HYD1 HYD2 IMPDSL IMPFERT IMPRAWSUG LNDFORCOV LNDRES LNDSUGPL LNDSUGPLIR LNDSUGPLRF NGCC RIVER RIVER_2 RIVWATAGR SOLPV1 SOLPV2 SUGFACTORY TD TD2 WINDPOWER ;
+
+# param ResultsPath := results;
+
+#####################
+#    Parameters     #
+#####################
+#
+param AccumulatedAnnualDemand default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ETH 1 1.03 1.061 1.093 1.126 1.159 1.194 1.23 1.267 1.305 1.344 1.384 1.426 1.469 1.513 1.558 1.605 1.653 1.702 1.754 1.806 1.86 1.916 1.974 2.033 2.094 2.157
+RAWSUG 0.5 0.51 0.519 0.529 0.538 0.548 0.558 0.567 0.577 0.587 0.596 0.606 0.615 0.625 0.635 0.644 0.654 0.663 0.673 0.683 0.692 0.702 0.712 0.721 0.731 0.74 0.75
+;
+
+param AnnualEmissionLimit default 99999 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+CO2 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 9999 0.2 0.18 0.16 0.14 0.12 0.1 0.09 0.08 0.07 0.06 0.05
+;
+
+param AnnualExogenousEmission default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+CO2 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+;
+
+param AvailabilityFactor default 1 :=
+;
+
+param CapacityFactor default 1 :=
+[SIMPLICITY,HYD1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4
+IN 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4
+SD 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34
+SN 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34
+WD 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56
+WN 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56 0.56
+[SIMPLICITY,RIVER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65
+IN 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65 0.65
+SD 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
+SN 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
+WD 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8
+WN 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8
+[SIMPLICITY,SOLPV1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
+IN 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+SD 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4
+SN 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+WD 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+WN 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+[SIMPLICITY,SOLPV2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+IN 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12
+SD 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
+SN 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15
+WD 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2
+WN 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
+[SIMPLICITY,WINDPOWER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+IN 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+SD 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+SN 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+WD 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+WN 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25
+;
+
+param CapacityOfOneTechnologyUnit default 0 :=
+;
+
+param CapacityToActivityUnit default 1 :
+BACKSTOP1 BACKSTOP2 BIOMASSPRO CHP ELEC_IMPORT GAS_EXTRACTION GAS_IMPORT GRID_EXP HYD1 HYD2 NGCC RIVER SOLPV1 SOLPV2 TD TD2 WINDPOWER:=
+SIMPLICITY 1 1 1 1 1 1 1 31.536 31.536 31.536 31.536 1 31.536 31.536 31.536 1 31.536
+;
+
+param CapitalCost default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+BACKSTOP1 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+BACKSTOP2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+ETHPLANT 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25
+GRID_EXP 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000 4000
+HYD1 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500 4500
+HYD2 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500 3500
+LNDSUGPLIR 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75 3.75
+LNDSUGPLRF 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75 2.75
+NGCC 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100
+SOLPV1 1700 1700 1700 1700 1700 1700 1600 1600 1600 1600 1600 1500 1500 1500 1500 1500 1400 1400 1400 1400 1400 1300 1300 1300 1300 1300 1200
+SOLPV2 2700 2700 2700 2700 2700 2700 2600 2600 2600 2600 2600 2500 2500 2500 2500 2500 2400 2400 2400 2400 2400 2300 2300 2300 2300 2300 2200
+SUGFACTORY 231.1 228.69 226.28 223.88 221.47 219.06 216.66 214.25 211.84 209.43 207.03 204.62 202.21 199.8 197.4 194.99 192.58 190.2 187.86 185.54 183.25 180.98 178.75 176.54 174.36 172.21 170.08
+WINDPOWER 1845 1808 1772 1736 1702 1667 1634 1601 1569 1538 1507 1477 1448 1419 1390 1362 1356 1349 1342 1335 1329 1322 1315 1309 1302 1296 1289
+;
+
+param CapitalCostStorage default 0 :=
+;
+
+param Conversionld default 0 :
+1:=
+ID 1
+IN 1
+SD 1
+SN 1
+WD 1
+WN 1
+;
+
+param Conversionlh default 0 :
+1 2:=
+ID 1 0
+IN 0 1
+SD 1 0
+SN 0 1
+WD 1 0
+WN 0 1
+;
+
+param Conversionls default 0 :
+1 2 3:=
+ID 0 1 0
+IN 0 1 0
+SD 0 0 1
+SN 0 0 1
+WD 1 0 0
+WN 1 0 0
+;
+
+param DaySplit default 0.00137 :=
+;
+
+param DaysInDayType default 7 :=
+;
+
+param DepreciationMethod default 1 :=
+;
+
+param DiscountRate default 0.05 :=
+;
+
+param EmissionActivityRatio default 0 :=
+[SIMPLICITY,GAS_EXTRACTION,CO2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+2 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+[SIMPLICITY,GAS_IMPORT,CO2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+2 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+;
+
+param EmissionsPenalty default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+CO2 7.5 7.5 7.5 7.5 7.5 7.5 8 8 8 8 8 8.5 8.5 8.5 8.5 8.5 9 9 9 9 9 9.5 9.5 9.5 9.5 9.5 10
+;
+
+param FixedCost default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ETHPLANT 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46 8.46
+GRID_EXP 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96
+HYD1 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65
+HYD2 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70
+NGCC 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44
+SUGFACTORY 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67 8.67
+TD 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96 0.96
+;
+
+param InputActivityRatio default 0 :=
+[SIMPLICITY,ETHPLANT,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251
+2 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251 0.0251
+[SIMPLICITY,ETHPLANT,MOLASSES,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519
+2 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519 0.1519
+[SIMPLICITY,GRID_EXP,SEC_EL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,HYD2,RIVERWATER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+2 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+[SIMPLICITY,LNDFORCOV,LAND,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDSUGPL,LAND,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDSUGPLIR,DSL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 .021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132
+2 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 .021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132
+[SIMPLICITY,LNDSUGPLIR,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515
+2 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515 0.000515
+[SIMPLICITY,LNDSUGPLIR,FER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064
+2 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064
+[SIMPLICITY,LNDSUGPLIR,LNDSUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDSUGPLIR,WATAGR,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634
+2 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634 0.634
+[SIMPLICITY,LNDSUGPLRF,DSL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 .021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132
+2 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 .021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132 0.021132
+[SIMPLICITY,LNDSUGPLRF,FER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064
+2 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064 0.000064
+[SIMPLICITY,LNDSUGPLRF,LNDSUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,NGCC,GAS,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992
+2 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992 1.992
+[SIMPLICITY,RIVWATAGR,WATIN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,SUGFACTORY,SUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52
+2 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52 7.52
+[SIMPLICITY,TD,SEC_EL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+;
+
+param MinStorageCharge default 0 :=
+;
+
+param ModelPeriodEmissionLimit default 99999 :=
+;
+
+param ModelPeriodExogenousEmission default 0 :=
+;
+
+param OperationalLife default 1 :
+BACKSTOP1 BACKSTOP2 BIOMASSPRO CHP ETHPLANT ELEC_IMPORT GAS_EXTRACTION GAS_IMPORT GRID_EXP HYD1 HYD2 IMPDSL IMPFERT IMPRAWSUG LNDFORCOV LNDRES LNDSUGPL LNDSUGPLIR LNDSUGPLRF NGCC RIVER RIVER_2 RIVWATAGR SOLPV1 SOLPV2 SUGFACTORY TD TD2 WINDPOWER:=
+SIMPLICITY 1 1 1 1 30 1 1 1 50 80 80 1 1 1 15 1 1 15 15 30 1 1 1 20 20 30 50 1 25
+;
+
+param OperationalLifeStorage default 0 :=
+;
+
+param OutputActivityRatio default 0 :=
+[SIMPLICITY,BACKSTOP1,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,BACKSTOP2,FEL2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,ETHPLANT,ETH,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,GAS_EXTRACTION,GAS,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,GAS_IMPORT,GAS,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,GRID_EXP,FEL2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82 0.82
+[SIMPLICITY,HYD1,SEC_EL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,HYD2,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,IMPDSL,DSL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,IMPFERT,FER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,IMPRAWSUG,RAWSUG,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDFORCOV,LANDFOREST,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDRES,LAND,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDSUGPL,LNDSUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,LNDSUGPLIR,SUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047 0.047
+[SIMPLICITY,LNDSUGPLRF,SUGCAN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376 0.0376
+[SIMPLICITY,NGCC,SEC_EL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,RIVER,RIVERWATER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,RIVER_2,WATIN,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,RIVWATAGR,WATAGR,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9
+[SIMPLICITY,SOLPV1,FEL2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,SOLPV2,FEL2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,SUGFACTORY,BAGASSE,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2 16.2
+[SIMPLICITY,SUGFACTORY,MOLASSES,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34 0.34
+[SIMPLICITY,SUGFACTORY,RAWSUG,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+[SIMPLICITY,TD,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95 0.95
+[SIMPLICITY,WINDPOWER,SEC_EL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+;
+
+param REMinProductionTarget default 0 :=
+;
+
+param RETagFuel default 0 :=
+;
+
+param RETagTechnology default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+SOLPV1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+SOLPV2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+WINDPOWER 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+;
+
+param ReserveMargin default 1 :=
+;
+
+param ReserveMarginTagFuel default 0 :=
+;
+
+param ReserveMarginTagTechnology default 0 :=
+;
+
+param ResidualCapacity default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ETHPLANT 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+LNDFORCOV 150 147.115 144.231 141.346 138.462 135.577 132.692 129.808 126.923 124.038 121.154 118.269 115.385 112.5 109.615 106.731 103.846 100.962 98.077 95.192 92.308 89.423 86.538 83.654 80.769 77.885 75
+LNDSUGPLIR 25 23.438 21.875 20.313 18.75 17.188 15.625 14.063 12.5 10.938 9.375 7.813 6.25 4.688 3.125 1.563 0 0 0 0 0 0 0 0 0 0 0
+LNDSUGPLRF 60 56.25 52.5 48.75 45 41.25 37.5 33.75 30 26.25 22.5 18.75 15 11.25 7.5 3.75 0 0 0 0 0 0 0 0 0 0 0
+NGCC 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0 0 0 0 0 0
+SUGFACTORY 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475 0.8475
+;
+
+param ResidualStorageCapacity default 999 :=
+;
+
+param SpecifiedAnnualDemand default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+FEL1 2.214 2.225 2.274 2.342 2.426 2.509 2.589 2.683 2.78 2.886 2.955 3.006 3.061 3.121 3.186 3.258 3.336 3.419 3.503 3.589 3.676 3.763 3.855 3.952 4.054 4.161 4.273
+FEL2 0 0 0 0 0.3 0.4 0.5 0.7 0.75 0.9 0.95 1 1.1 1.2 1.25 1.28 1.3 1.35 1.5 1.55 1.6 1.64 1.7 1.78 1.85 1.92 2.05
+;
+
+param SpecifiedDemandProfile default 0 :=
+[SIMPLICITY,FEL1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12
+IN 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08
+SD 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15
+SN 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+WD 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4
+WN 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2
+[SIMPLICITY,FEL2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12 0.12
+IN 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08 0.08
+SD 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15
+SN 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
+WD 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4
+WN 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2
+;
+
+param StorageLevelStart default 0 :=
+;
+
+param StorageMaxChargeRate default 0 :=
+;
+
+param StorageMaxDischargeRate default 0 :=
+;
+
+param TechnologyFromStorage default 0 :=
+[SIMPLICITY,HYD2,*,*]:
+1 2:=
+DAM 0 1
+;
+
+param TechnologyToStorage default 0 :=
+[SIMPLICITY,HYD2,*,*]:
+1 2:=
+DAM 1 0
+;
+
+param TotalAnnualMaxCapacity default 99999 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+GAS_EXTRACTION 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
+HYD1 0 0 0 0 0 0 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02 0.02
+HYD2 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
+RIVER 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+;
+
+param TotalAnnualMaxCapacityInvestment default 99999 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+HYD1 0 0 0 0 0 0 0.02 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+HYD2 0 0 0 0 0 0 0 0 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
+LNDSUGPLIR 5 5 5 5 5 5 5 5 5 5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 10 10 10 10 10 10 10
+;
+
+param TotalAnnualMinCapacity default 0 :=
+;
+
+param TotalAnnualMinCapacityInvestment default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+HYD1 0 0 0 0 0 0 0.02 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+;
+
+param TotalTechnologyAnnualActivityLowerLimit default 0 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+LNDFORCOV 150 147.115 144.231 141.346 138.462 135.577 132.692 129.808 126.923 124.038 121.154 118.269 115.385 112.5 109.615 106.731 103.846 100.962 98.077 95.192 92.308 89.423 86.538 83.654 80.769 77.885 75
+;
+
+param TotalTechnologyAnnualActivityUpperLimit default 99999 :=
+[SIMPLICITY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+LNDRES 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300 300
+RIVER 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+;
+
+param TotalTechnologyModelPeriodActivityLowerLimit default 0 :=
+;
+
+param TotalTechnologyModelPeriodActivityUpperLimit default 99999 :=
+;
+
+param TradeRoute default 0 :=
+;
+
+param VariableCost default 0 :=
+[SIMPLICITY,BACKSTOP1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+[SIMPLICITY,BACKSTOP2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+[SIMPLICITY,ETHPLANT,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89
+2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+[SIMPLICITY,GAS_EXTRACTION,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 7.5 7.5 7.5 7.5 7.5 7.5 8 8 8 8 8 8.5 8.5 8.5 8.5 8.5 9 9 9 9 9 9.5 9.5 9.5 9.5 9.5 10
+2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+[SIMPLICITY,GAS_IMPORT,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 8 8 8.5 8.5 8.5 8.5 8.5 9 9 9 9 9 9.5 9.5 9.5 9.5 9.5 10 10 10 10 10.5 10.5 10.5 10.5 10.5 11
+2 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999 999999
+[SIMPLICITY,IMPDSL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 15.647 17.365 19.083 20.801 22.519 24.237 25.219 26.201 27.183 28.164 29.146 30.128 31.11 32.091 33.073 34.055 34.454 34.853 35.252 35.65 36.049 36.448 36.847 37.246 37.645 38.043 38.043
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,IMPFERT,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400 400
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,IMPRAWSUG,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331 331
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,LNDFORCOV,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,LNDRES,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,LNDSUGPL,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,LNDSUGPLIR,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75 0.75
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,LNDSUGPLRF,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55 0.55
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,RIVER_2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07
+[SIMPLICITY,RIVWATAGR,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,SOLPV1,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54
+2 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54 2.54
+[SIMPLICITY,SOLPV2,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5
+2 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5 3.5
+[SIMPLICITY,SUGFACTORY,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89 2.89
+2 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999 99999
+[SIMPLICITY,WINDPOWER,*,*]:
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+1 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167
+2 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167 4.167
+;
+
+param YearSplit default 0 :
+2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040:=
+ID 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667
+IN 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833
+SD 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667
+SN 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833 0.0833
+WD 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333 0.3333
+WN 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667 0.1667
+;
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 3bf9e04..f17a3ac 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -1,9 +1,9 @@
+from pytest import mark
+
 import os
 from subprocess import run
 from tempfile import NamedTemporaryFile, mkdtemp
 
-from pytest import mark
-
 from otoole import __version__
 
 
@@ -13,22 +13,49 @@ class TestConvert:
         assert result.stdout.strip().decode() == str(__version__)
 
     temp = mkdtemp()
-    temp_excel = NamedTemporaryFile(suffix="xlsx")
-    temp_datafile = NamedTemporaryFile(suffix="dat")
+    temp_excel = NamedTemporaryFile(suffix=".xlsx")
+    temp_datafile = NamedTemporaryFile(suffix=".dat")
     simplicity = os.path.join("tests", "fixtures", "simplicity.txt")
+    config_path = os.path.join("tests", "fixtures", "config.yaml")
 
     test_data = [
-        (["otoole", "convert", "--help"], "usage: otoole convert [-h]"),
-        (["otoole", "convert", "datafile", "datapackage", simplicity, temp], ""),
-        (["otoole", "convert", "datafile", "excel", simplicity, temp_excel.name], ""),
+        (["otoole", "-v", "convert", "--help"], "usage: otoole convert [-h]"),
+        (
+            [
+                "otoole",
+                "-v",
+                "convert",
+                "datafile",
+                "datapackage",
+                simplicity,
+                temp,
+                config_path,
+            ],
+            "",
+        ),
         (
             [
                 "otoole",
+                "-v",
+                "convert",
+                "datafile",
+                "excel",
+                simplicity,
+                temp_excel.name,
+                config_path,
+            ],
+            "",
+        ),
+        (
+            [
+                "otoole",
+                "-v",
                 "convert",
                 "datafile",
                 "datafile",
                 simplicity,
                 temp_datafile.name,
+                config_path,
             ],
             "",
         ),
@@ -40,10 +67,12 @@ class TestConvert:
     def test_convert_commands(self, commands, expected):
         actual = run(commands, capture_output=True)
         assert expected in str(actual.stdout)
+        print(" ".join(commands))
+        assert actual.returncode == 0, print(actual.stdout)
 
     test_errors = [
         (
-            ["otoole", "convert", "datafile", "cplex", "x", "y"],
+            ["otoole", "convert", "datafile", "cplex", "x", "y", config_path],
             "error: argument to_format: invalid choice: 'cplex'",
         )
     ]
@@ -52,3 +81,34 @@ class TestConvert:
     def test_convert_error(self, commands, expected):
         actual = run(commands, capture_output=True)
         assert expected in str(actual.stderr)
+
+    def test_convert_datafile_datafile_no_user_config(self):
+        simplicity = os.path.join("tests", "fixtures", "simplicity.txt")
+        temp_datafile = NamedTemporaryFile(suffix=".dat")
+        commands = [
+            "otoole",
+            "convert",
+            "datafile",
+            "datafile",
+            simplicity,
+            temp_datafile.name,
+        ]
+        actual = run(commands, capture_output=True)
+        assert actual.returncode == 2
+
+    def test_convert_datafile_datafile_with_user_config(self):
+        simplicity = os.path.join("tests", "fixtures", "simplicity.txt")
+        user_config = os.path.join("tests", "fixtures", "config.yaml")
+        temp_datafile = NamedTemporaryFile(suffix=".dat")
+        commands = [
+            "otoole",
+            "-vvv",
+            "convert",
+            "datafile",
+            "datafile",
+            simplicity,
+            temp_datafile.name,
+            user_config,
+        ]
+        actual = run(commands, capture_output=True)
+        assert actual.returncode == 0
diff --git a/tests/test_convert.py b/tests/test_convert.py
index 14a494f..cb89af6 100644
--- a/tests/test_convert.py
+++ b/tests/test_convert.py
@@ -35,10 +35,10 @@ from otoole import Context, ReadExcel, WriteCsv, WriteDatafile
 
 
 class TestConvert:
-    def test_convert_excel_to_datafile(self):
+    def test_convert_excel_to_datafile(self, user_config):
 
-        read_strategy = ReadExcel()
-        write_strategy = WriteDatafile()
+        read_strategy = ReadExcel(user_config)
+        write_strategy = WriteDatafile(user_config)
         context = Context(read_strategy, write_strategy)
 
         tmpfile = NamedTemporaryFile()
@@ -55,10 +55,10 @@ class TestConvert:
         assert actual[2] == b"09_ROK d_bld_2_coal_products 2017 20.8921\n"
         assert actual[8996] == b"param default 1 : DepreciationMethod :=\n"
 
-    def test_convert_excel_to_csv(self):
+    def test_convert_excel_to_csv(self, user_config):
 
-        read_strategy = ReadExcel()
-        write_strategy = WriteCsv()
+        read_strategy = ReadExcel(user_config)
+        write_strategy = WriteCsv(user_config)
         context = Context(read_strategy, write_strategy)
 
         tmpfile = TemporaryDirectory()
diff --git a/tests/test_read_strategies.py b/tests/test_read_strategies.py
index d1cb4ab..a8f06e6 100644
--- a/tests/test_read_strategies.py
+++ b/tests/test_read_strategies.py
@@ -108,8 +108,8 @@ class TestReadCplex:
     ]
 
     @mark.parametrize("cplex_input,expected", test_data, ids=["short", "long"])
-    def test_read_cplex_to_dataframe(self, cplex_input, expected):
-        cplex_reader = ReadCplex()
+    def test_read_cplex_to_dataframe(self, cplex_input, expected, user_config):
+        cplex_reader = ReadCplex(user_config=user_config)
 
         input_data = {
             "YEAR": pd.DataFrame(data=list(range(2015, 2071, 1)), columns=["VALUE"])
@@ -122,10 +122,10 @@ class TestReadCplex:
 
     test_data_mid = [(cplex_short, cplex_mid_short), (cplex_long, cplex_mid_long)]
 
-    def test_read_empty_cplex_to_dataframe(self):
+    def test_read_empty_cplex_to_dataframe(self, user_config):
         cplex_input = self.cplex_empty
 
-        cplex_reader = ReadCplex()
+        cplex_reader = ReadCplex(user_config)
 
         input_data = {
             "YEAR": pd.DataFrame(data=list(range(2015, 2071, 1)), columns=["VALUE"])
@@ -154,15 +154,15 @@ class TestReadCplex:
     @mark.parametrize(
         "cplex_input,expected", test_data_to_cplex, ids=["empty", "short", "long"]
     )
-    def test_convert_cplex_to_df(self, cplex_input, expected):
+    def test_convert_cplex_to_df(self, cplex_input, expected, user_config):
 
         data = cplex_input.split("\t")
         variable = data[0]
-        cplex_reader = ReadCplex()
+        cplex_reader = ReadCplex(user_config=user_config)
         actual = cplex_reader.convert_df([data], variable, 2015, 2070)
         pd.testing.assert_frame_equal(actual, expected, check_index_type=False)
 
-    def test_convert_lines_to_df_empty(self):
+    def test_convert_lines_to_df_empty(self, user_config):
 
         data = [
             [
@@ -181,7 +181,7 @@ class TestReadCplex:
             ]
         ]
         variable = "AnnualFixedOperatingCost"
-        cplex_reader = ReadCplex()
+        cplex_reader = ReadCplex(user_config)
         actual = cplex_reader.convert_df(data, variable, 2015, 2023)
         pd.testing.assert_frame_equal(
             actual,
@@ -238,9 +238,9 @@ RateOfActivity(SIMPLICITY,ID,FEL1,1,2017) 1.68590281943611
 """
     )
 
-    def test_convert_to_dataframe(self):
+    def test_convert_to_dataframe(self, user_config):
         input_file = self.gurobi_data
-        reader = ReadGurobi()
+        reader = ReadGurobi(user_config)
         with StringIO(input_file) as file_buffer:
             actual = reader._convert_to_dataframe(file_buffer)
         print(actual)
@@ -260,9 +260,9 @@ RateOfActivity(SIMPLICITY,ID,FEL1,1,2017) 1.68590281943611
 
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_solution_to_dataframe(self):
+    def test_solution_to_dataframe(self, user_config):
         input_file = self.gurobi_data
-        reader = ReadGurobi()
+        reader = ReadGurobi(user_config)
         with StringIO(input_file) as file_buffer:
             actual = reader.read(file_buffer)
         print(actual)
@@ -337,12 +337,14 @@ class TestReadCbc:
     ]
 
     @mark.parametrize("cbc_input,expected", test_data)
-    def test_read_cbc_to_otoole_dataframe(self, cbc_input, expected):
+    def test_read_cbc_to_otoole_dataframe(self, cbc_input, expected, user_config):
         with StringIO(cbc_input) as file_buffer:
-            actual = ReadCbc().read(file_buffer, kwargs={"input_data": {}})[0]["Trade"]
+            actual = ReadCbc(user_config).read(file_buffer, kwargs={"input_data": {}})[
+                0
+            ]["Trade"]
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_read_cbc_dataframe_to_otoole_dataframe(self):
+    def test_read_cbc_dataframe_to_otoole_dataframe(self, user_config):
 
         prelim_data = pd.DataFrame(
             data=[
@@ -354,7 +356,7 @@ class TestReadCbc:
             ],
             columns=["Variable", "Index", "Value"],
         )
-        actual = ReadCbc()._convert_wide_to_long(prelim_data)["Trade"]
+        actual = ReadCbc(user_config)._convert_wide_to_long(prelim_data)["Trade"]
         pd.testing.assert_frame_equal(actual, self.otoole_data)
 
     test_data_4 = [
@@ -426,8 +428,8 @@ class TestReadCbc:
     test_data = [(total_cost_cbc, total_cost_cbc_mid)]
 
     @mark.parametrize("cbc_input,expected", test_data, ids=["TotalDiscountedCost"])
-    def test_read_cbc_to_dataframe(self, cbc_input, expected):
-        cbc_reader = ReadCbc()
+    def test_read_cbc_to_dataframe(self, cbc_input, expected, user_config):
+        cbc_reader = ReadCbc(user_config)
         with StringIO(cbc_input) as file_buffer:
             actual = cbc_reader._convert_to_dataframe(file_buffer)
         pd.testing.assert_frame_equal(actual, expected)
@@ -463,8 +465,8 @@ class TestReadCbc:
         test_data_2,
         ids=["TotalDiscountedCost", "AnnualEmissions1"],
     )
-    def test_convert_cbc_to_csv_long(self, results, expected):
-        cbc_reader = ReadCbc()
+    def test_convert_cbc_to_csv_long(self, results, expected, user_config):
+        cbc_reader = ReadCbc(user_config=user_config)
         actual = cbc_reader._convert_wide_to_long(results)
         assert isinstance(actual, dict)
         for name, df in actual.items():
@@ -477,8 +479,10 @@ class TestReadCbc:
         test_data_3,
         ids=["TotalDiscountedCost"],
     )
-    def test_convert_cbc_to_csv_long_read(self, cbc_solution, input_data, expected):
-        cbc_reader = ReadCbc()
+    def test_convert_cbc_to_csv_long_read(
+        self, cbc_solution, input_data, expected, user_config
+    ):
+        cbc_reader = ReadCbc(user_config=user_config)
         with StringIO(cbc_solution) as file_buffer:
             actual = cbc_reader.read(file_buffer, kwargs={"input_data": input_data})[0][
                 "TotalDiscountedCost"
@@ -486,7 +490,7 @@ class TestReadCbc:
         assert isinstance(actual, pd.DataFrame)
         pd.testing.assert_frame_equal(actual, expected["TotalDiscountedCost"])
 
-    def test_calculate_results(self):
+    def test_calculate_results(self, user_config):
         cbc_results = {
             "RateOfActivity": pd.DataFrame(
                 data=[
@@ -547,14 +551,14 @@ class TestReadCbc:
             columns=["REGION", "EMISSION", "YEAR", "VALUE"],
         ).set_index(["REGION", "EMISSION", "YEAR"])
 
-        cbc_reader = ReadCbc()
+        cbc_reader = ReadCbc(user_config)
         actual = cbc_reader.calculate_results(cbc_results, input_data)
         assert isinstance(actual, dict)
         pd.testing.assert_frame_equal(actual["AnnualEmissions"], expected)
 
-    def test_solution_to_dataframe(self):
+    def test_solution_to_dataframe(self, user_config):
         input_file = self.total_cost_cbc
-        reader = ReadCbc()
+        reader = ReadCbc(user_config)
         with StringIO(input_file) as file_buffer:
             actual = reader.read(file_buffer)
         expected = self.total_cost_otoole_df
@@ -576,9 +580,9 @@ class TestReadCbc:
 """
     )
 
-    def test_manage_infeasible_variables(self):
+    def test_manage_infeasible_variables(self, user_config):
         input_file = self.cbc_infeasible
-        reader = ReadCbc()
+        reader = ReadCbc(user_config)
         with StringIO(input_file) as file_buffer:
             actual = reader._convert_to_dataframe(file_buffer)
         expected = pd.DataFrame(
@@ -601,9 +605,9 @@ class TestReadCbc:
 class TestCleanOnRead:
     """Tests that a datapackage is cleaned and indexed upon reading"""
 
-    def test_index_dtypes_available(self):
-        reader = ReadMemory({})
-        config = reader._input_config
+    def test_index_dtypes_available(self, user_config):
+        reader = ReadMemory({}, user_config=user_config)
+        config = reader.user_config
         assert "index_dtypes" in config["AccumulatedAnnualDemand"].keys()
         actual = config["AccumulatedAnnualDemand"]["index_dtypes"]
         assert actual == {
@@ -613,7 +617,7 @@ class TestCleanOnRead:
             "VALUE": "float",
         }
 
-    def test_remove_empty_lines(self):
+    def test_remove_empty_lines(self, user_config):
 
         data = [
             ["SIMPLICITY", "ETH", 2014, 1.0],
@@ -624,7 +628,7 @@ class TestCleanOnRead:
         df = pd.DataFrame(data=data, columns=["REGION", "FUEL", "YEAR", "VALUE"])
         parameters = {"AccumulatedAnnualDemand": df}
 
-        reader = ReadMemory(parameters)
+        reader = ReadMemory(parameters, user_config=user_config)
         actual, _ = reader.read()
 
         expected = {
@@ -644,7 +648,7 @@ class TestCleanOnRead:
             actual["AccumulatedAnnualDemand"], expected["AccumulatedAnnualDemand"]
         )
 
-    def test_change_types(self):
+    def test_change_types(self, user_config):
 
         data = [
             ["SIMPLICITY", "ETH", 2014.0, 1],
@@ -655,7 +659,7 @@ class TestCleanOnRead:
         ).astype({"REGION": str, "FUEL": str, "YEAR": float, "VALUE": int})
         parameters = {"AccumulatedAnnualDemand": df}
 
-        reader = ReadMemory(parameters)
+        reader = ReadMemory(parameters, user_config=user_config)
         actual, _ = reader.read()
 
         expected = {
@@ -677,7 +681,7 @@ class TestCleanOnRead:
 
 
 class TestReadMemoryStrategy:
-    def test_read_memory(self):
+    def test_read_memory(self, user_config):
 
         data = [
             ["SIMPLICITY", "ETH", 2014, 1.0],
@@ -688,7 +692,7 @@ class TestReadMemoryStrategy:
         df = pd.DataFrame(data=data, columns=["REGION", "FUEL", "YEAR", "VALUE"])
         parameters = {"AccumulatedAnnualDemand": df}
 
-        actual, default_values = ReadMemory(parameters).read()
+        actual, default_values = ReadMemory(parameters, user_config).read()
 
         expected = {
             "AccumulatedAnnualDemand": pd.DataFrame(
@@ -701,18 +705,50 @@ class TestReadMemoryStrategy:
             actual["AccumulatedAnnualDemand"], expected["AccumulatedAnnualDemand"]
         )
 
+    def test_read_memory_user_config(self, user_config):
+
+        data = [
+            ["SIMPLICITY", "ETH", 2014, 1.0],
+            ["SIMPLICITY", "RAWSUG", 2014, 0.5],
+            ["SIMPLICITY", "ETH", 2015, 1.03],
+            ["SIMPLICITY", "RAWSUG", 2015, 0.51],
+        ]
+        df = pd.DataFrame(data=data, columns=["REGION", "FUEL", "YEAR", "VALUE"])
+        parameters = {"AccumulatedAnnualDemand": df}
+
+        actual, default_values = ReadMemory(parameters, user_config=user_config).read()
+
+        expected = {
+            "AccumulatedAnnualDemand": pd.DataFrame(
+                data=data, columns=["REGION", "FUEL", "YEAR", "VALUE"]
+            ).set_index(["REGION", "FUEL", "YEAR"])
+        }
+
+        assert "AccumulatedAnnualDemand" in actual.keys()
+        pd.testing.assert_frame_equal(
+            actual["AccumulatedAnnualDemand"], expected["AccumulatedAnnualDemand"]
+        )
+
+        assert default_values["AccumulatedAnnualDemand"] == 0
+
 
 class TestConfig:
-    def test_read_config(self):
+    def test_read_config(self, user_config):
 
-        read = ReadDatafile()
+        read = ReadDatafile(user_config=user_config)
 
-        actual = read._read_config()
+        actual = read.user_config
         expected = {
             "default": 0,
             "dtype": "float",
             "indices": ["REGION", "FUEL", "YEAR"],
             "type": "param",
+            "index_dtypes": {
+                "FUEL": "str",
+                "REGION": "str",
+                "VALUE": "float",
+                "YEAR": "int",
+            },
         }
         assert actual["AccumulatedAnnualDemand"] == expected
 
@@ -732,7 +768,7 @@ class TestReadDatafile:
             end;"""
         )
 
-    def test_convert_amply_to_dataframe(self):
+    def test_convert_amply_to_dataframe(self, user_config):
 
         config = {
             "VariableCost": {
@@ -778,7 +814,7 @@ class TestReadDatafile:
     2 999999.0;"""
         )
 
-        read = ReadDatafile()
+        read = ReadDatafile(user_config=user_config)
 
         actual = read._convert_amply_to_dataframe(amply, config)
         expected = pd.DataFrame(
@@ -792,7 +828,7 @@ class TestReadDatafile:
         )
         pd.testing.assert_frame_equal(actual["VariableCost"], expected)
 
-    def test_convert_amply_data_to_list_of_lists(self):
+    def test_convert_amply_data_to_list_of_lists(self, user_config):
 
         data = {
             "SIMPLICITY": {
@@ -806,34 +842,34 @@ class TestReadDatafile:
             ["SIMPLICITY", "GAS_EXTRACTION", 1.0, 2014.0, 7.5],
             ["SIMPLICITY", "GAS_EXTRACTION", 2.0, 2014.0, 999999.0],
         ]
-        read = ReadDatafile()
+        read = ReadDatafile(user_config=user_config)
         actual = read._convert_amply_data_to_list(data)
         assert actual == expected
 
-    def test_load_parameters(self):
+    def test_load_parameters(self, user_config):
 
         config = {"TestParameter": {"type": "param", "indices": ["index1", "index2"]}}
-        read = ReadDatafile()
+        read = ReadDatafile(user_config=user_config)
         actual = read._load_parameter_definitions(config)
         expected = "param TestParameter {index1,index2};\n"
         assert actual == expected
 
-    def test_load_sets(self):
+    def test_load_sets(self, user_config):
 
         config = {"TestSet": {"type": "set"}}
 
-        read = ReadDatafile()
+        read = ReadDatafile(user_config=user_config)
         actual = read._load_parameter_definitions(config)
         expected = "set TestSet;\n"
         assert actual == expected
 
-    def test_catch_error_no_parameter(self, caplog):
+    def test_catch_error_no_parameter(self, caplog, user_config):
         """Fix for https://github.com/OSeMOSYS/otoole/issues/70 where parameter in
         datafile but not in config causes error.  Instead, throw warning (and advise
         that user should use a custom configuration).
         """
-        read = ReadDatafile()
-        config = read.input_config
+        read = ReadDatafile(user_config=user_config)
+        config = read.user_config
         amply_datafile = amply = Amply(
             """set REGION;
             set TECHNOLOGY;
@@ -849,10 +885,10 @@ class TestReadDatafile:
 
 
 class TestReadExcel:
-    def test_read_excel_yearsplit(self):
+    def test_read_excel_yearsplit(self, user_config):
         """ """
         spreadsheet = os.path.join("tests", "fixtures", "combined_inputs.xlsx")
-        reader = ReadExcel()
+        reader = ReadExcel(user_config=user_config)
         actual, _ = reader.read(spreadsheet)
         data = [
             ["IW0016", 2017, 0.238356164],
@@ -900,7 +936,7 @@ class TestReadExcel:
 
         assert (actual_data == expected).all()
 
-    def test_narrow_parameters(self):
+    def test_narrow_parameters(self, user_config):
         data = [
             ["IW0016", 0.238356164, 0.238356164, 0.238356164],
             ["IW1624", 0.119178082, 0.119178082, 0.119178082],
@@ -910,7 +946,7 @@ class TestReadExcel:
         config_details = ["TIMESLICE", "YEAR"]
         name = "YearSplit"
 
-        reader = ReadExcel()
+        reader = ReadExcel(user_config=user_config)
         actual = reader._check_parameter(df, config_details, name)
         data = [
             ["IW0016", 2017, 0.238356164],
@@ -930,7 +966,7 @@ class TestReadExcel:
         )
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_check_index(self):
+    def test_check_index(self, user_config):
 
         data = [
             ["IW0016", 2017, 0.238356164],
@@ -943,13 +979,13 @@ class TestReadExcel:
             ["IH0012", 2018, 0.071232876],
             ["IH0012", 2019, 0.071232876],
         ]
-        fixture = {
+        df = {
             "YearSplit": pd.DataFrame(data, columns=["TIMESLICE", "YEAR", "VALUE"])
             .astype({"YEAR": object})
             .set_index(["TIMESLICE", "YEAR"])
         }
-        reader = ReadExcel()
-        actual = reader._check_index(fixture)
+        reader = ReadExcel(user_config=user_config)
+        actual = reader._check_index(df)
         expected = {
             "YearSplit": pd.DataFrame(
                 data, columns=["TIMESLICE", "YEAR", "VALUE"]
diff --git a/tests/test_visualise.py b/tests/test_visualise.py
index 77454dd..740fddc 100644
--- a/tests/test_visualise.py
+++ b/tests/test_visualise.py
@@ -1,3 +1,5 @@
+import pytest
+
 import tempfile
 
 from otoole.visualise import create_res
@@ -5,6 +7,10 @@ from otoole.visualise import create_res
 url = "tests/fixtures/simplicity-v0.2.1.zip"
 
 
+@pytest.mark.skip(
+    "pydot deprecated, requires replacement with pygraphviz "
+    + "(https://github.com/OSeMOSYS/otoole/issues/121)"
+)
 def test_create_res():
 
     _, path_to_resfile = tempfile.mkstemp(suffix=".pdf")
diff --git a/tests/test_write_strategies.py b/tests/test_write_strategies.py
index 71ec736..9daa8a7 100644
--- a/tests/test_write_strategies.py
+++ b/tests/test_write_strategies.py
@@ -1,13 +1,14 @@
 import io
 import pandas as pd
+from tempfile import NamedTemporaryFile
 
 from otoole.write_strategies import WriteDatafile, WriteExcel
 
 
 class TestWriteExcel:
-    def test_form_empty_parameter_with_defaults(self):
+    def test_form_empty_parameter_with_defaults(self, user_config):
 
-        convert = WriteExcel()  # typing: WriteExcel
+        convert = WriteExcel(user_config)  # typing: WriteExcel
 
         data = []
 
@@ -20,9 +21,9 @@ class TestWriteExcel:
         ).set_index(["REGION", "FUEL"])
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_form_empty_two_index_param_with_defaults(self):
+    def test_form_empty_two_index_param_with_defaults(self, user_config):
 
-        convert = WriteExcel()  # typing: WriteExcel
+        convert = WriteExcel(user_config)  # typing: WriteExcel
 
         df = pd.DataFrame(data=[], columns=["REGION", "VALUE"]).set_index("REGION")
         actual = convert._form_parameter(df, "test_parameter", 0)
@@ -31,9 +32,9 @@ class TestWriteExcel:
         )
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_form_two_index_param(self):
+    def test_form_two_index_param(self, user_config):
 
-        convert = WriteExcel()  # typing: WriteExcel
+        convert = WriteExcel(user_config)  # typing: WriteExcel
 
         df = pd.DataFrame(
             data=[["SIMPLICITY", 0.10], ["UTOPIA", 0.20]], columns=["REGION", "VALUE"]
@@ -44,9 +45,9 @@ class TestWriteExcel:
         print(actual, expected)
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_form_one_columns(self):
+    def test_form_one_columns(self, user_config):
 
-        convert = WriteExcel()  # typing: WriteExcel
+        convert = WriteExcel(user_config)  # typing: WriteExcel
 
         data = ["A", "B", "C"]
 
@@ -56,9 +57,9 @@ class TestWriteExcel:
         print(actual, expected)
         pd.testing.assert_frame_equal(actual, expected)
 
-    def test_form_three_columns(self):
+    def test_form_three_columns(self, user_config):
 
-        convert = WriteExcel()  # typing: WriteExcel
+        convert = WriteExcel(user_config)  # typing: WriteExcel
 
         data = [["SIMPLICITY", "COAL", 2015, 41], ["SIMPLICITY", "COAL", 2016, 42]]
 
@@ -78,11 +79,23 @@ class TestWriteExcel:
 
         pd.testing.assert_frame_equal(actual, expected)
 
+    def test_write_out_empty_dataframe(self, user_config):
+
+        temp_excel = NamedTemporaryFile(suffix=".xlsx")
+        handle = pd.ExcelWriter(temp_excel.name)
+        convert = WriteExcel(user_config)
+
+        df = pd.DataFrame(
+            data=None, columns=["REGION", "TECHNOLOGY", "YEAR", "VALUE"]
+        ).set_index(["REGION", "TECHNOLOGY", "YEAR"])
+
+        convert._write_parameter(df, "AvailabilityFactor", handle, default=0)
+
 
 class TestWriteDatafile:
-    def test_write_empty_parameter_with_defaults(self):
+    def test_write_empty_parameter_with_defaults(self, user_config):
 
-        convert = WriteDatafile()  # typing: WriteDatafile
+        convert = WriteDatafile(user_config)  # typing: WriteDatafile
 
         data = []
 
@@ -98,7 +111,7 @@ class TestWriteDatafile:
         for actual_line, expected_line in zip(actual, expected):
             assert actual_line == expected_line
 
-    def test_write_parameter_as_tabbing_format(self):
+    def test_write_parameter_as_tabbing_format(self, user_config):
 
         data = [["SIMPLICITY", "BIOMASS", 0.95969], ["SIMPLICITY", "ETH1", 4.69969]]
 
@@ -107,7 +120,7 @@ class TestWriteDatafile:
         )
 
         stream = io.StringIO()
-        convert = WriteDatafile()
+        convert = WriteDatafile(user_config)
         convert._write_parameter(df, "test_parameter", stream, 0)
 
         stream.seek(0)
@@ -122,7 +135,7 @@ class TestWriteDatafile:
         for actual_line, expected_line in zip(actual, expected):
             assert actual_line == expected_line
 
-    def test_write_parameter_skip_defaults(self):
+    def test_write_parameter_skip_defaults(self, user_config):
 
         data = [
             ["SIMPLICITY", "BIOMASS", 0.95969],
@@ -136,7 +149,7 @@ class TestWriteDatafile:
         )
 
         stream = io.StringIO()
-        convert = WriteDatafile()
+        convert = WriteDatafile(user_config)
         convert._write_parameter(df, "test_parameter", stream, -1)
 
         stream.seek(0)
@@ -151,14 +164,14 @@ class TestWriteDatafile:
         for actual_line, expected_line in zip(actual, expected):
             assert actual_line == expected_line
 
-    def test_write_set(self):
+    def test_write_set(self, user_config):
 
         data = [["BIOMASS"], ["ETH1"]]
 
         df = pd.DataFrame(data=data, columns=["VALUE"])
 
         stream = io.StringIO()
-        convert = WriteDatafile()
+        convert = WriteDatafile(user_config)
         convert._write_set(df, "TECHNOLOGY", stream)
 
         stream.seek(0)