"""Converts an OSeMOSYS solution file from CPLEX, CBC or GLPK into CBC or CSV format
"""
import argparse
from typing import List, Tuple
[docs]class ConvertLine(object):
"""Abstract class which defines the interface to the family of convertors
Inherit this class and implement the ``_do_it()`` method to produce the
data to be written out into a new format
Example
-------
>>> cplex_line = "AnnualCost REGION CDBACKSTOP 1.0 0.0 137958.8400384134"
>>> convertor = RegionTechnology()
>>> convertor.convert()
VariableName(REGION,TECHCODE01,2015) 42.69 0\\n
VariableName(REGION,TECHCODE01,2017) 137958.84 0\\n
"""
def __init__(self, data: List, start_year: int, end_year: int, output_format='cbc'):
self.data = data
self.start_year = start_year
self.end_year = end_year
self.output_format = output_format
def _do_it(self) -> Tuple:
raise NotImplementedError()
[docs] def convert(self) -> List[str]:
if self.output_format == 'cbc':
convert = self.convert_cbc()
elif self.output_format == 'csv':
convert = self.convert_csv()
return convert
[docs] def convert_csv(self) -> List[str]:
"""Format the data for writing to a csv file
"""
data = []
variable, dimensions, values = self._do_it()
for index, value in enumerate(values):
year = self.start_year + index
if (value not in ["0.0", "0", ""]) and (year <= self.end_year):
try:
value = float(value)
except ValueError:
value = 0
full_dims = ",".join(dimensions + (str(year),))
formatted_data = '{0},"{1}",{2}\n'.format(
variable,
full_dims,
value
)
data.append(formatted_data)
return data
[docs] def convert_cbc(self) -> List[str]:
"""Format the data for writing to a CBC file
"""
cbc_data = []
variable, dimensions, values = self._do_it()
for index, value in enumerate(values):
year = self.start_year + index
if (value not in ["0.0", "0", ""]) and (year <= self.end_year):
try:
value = float(value)
except ValueError:
value = 0
full_dims = ",".join(dimensions + (str(year),))
formatted_data = "0 {0}({1}) {2} 0\n".format(
variable,
full_dims,
value
)
cbc_data.append(formatted_data)
return cbc_data
[docs]class RegionTimeSliceTechnologyMode(ConvertLine):
def _do_it(self) -> Tuple:
"""Produces output indexed by Region, Timeslice, Tech and Mode
``0 VariableName(REGION,SD1D,TECHCODE01,2,2015) 42.69 0\n``
"""
variable = self.data[0]
region = self.data[1]
timeslice = self.data[2]
technology = self.data[3]
mode = self.data[4]
values = self.data[5:]
dimensions = (region, timeslice, technology, mode)
return (variable, dimensions, values)
[docs]class RegionTechnology(ConvertLine):
def _do_it(self) -> Tuple:
"""Produces output indexed by dimensions Region and Technology
``0 VariableName(REGION,TECHCODE01,2015) 42.69 0\n``
"""
variable = self.data[0]
region = self.data[1]
technology = self.data[2]
dimensions = (region, technology)
values = self.data[3:]
return (variable, dimensions, values)
[docs]def process_line(line: str,
start_year: int,
end_year: int,
output_format: str) -> List[str]:
"""Processes an individual line in a CPLEX file
A different ConvertLine implementation is chosen depending upon the
variable name
Arguments
---------
line: str
start_year: int
end_year: int
output_format: str
The file format required - either ``csv`` or ``cbc``
"""
row_as_list = line.split('\t')
variable = row_as_list[0]
if variable in ['NewCapacity',
'TotalCapacityAnnual',
'CapitalInvestment',
'AnnualFixedOperatingCost',
'AnnualVariableOperatingCost']:
convertor = RegionTechnology(row_as_list, start_year, end_year, output_format).convert()
elif variable in ['RateOfActivity']:
convertor = RegionTimeSliceTechnologyMode(row_as_list, start_year, end_year, output_format).convert()
else:
convertor = []
return convertor
[docs]def convert_cplex_file(cplex_filename: str, output_filename: str,
start_year=2015, end_year=2070,
output_format='cbc'):
"""Converts a CPLEX solution file into that of the CBC solution file
Arguments
---------
cplex_filename : str
Path to the transformed CPLEX solution file
output_filename : str
Path for the processed data to be written to
"""
with open(output_filename, 'w') as cbc_file:
with open(cplex_filename, 'r') as cplex_file:
for linenum, line in enumerate(cplex_file):
try:
convertor = process_line(line, start_year, end_year, output_format)
if convertor:
cbc_file.writelines(convertor)
except ValueError:
msg = "Error caused at line {}: {}"
raise ValueError(msg.format(linenum, line))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Convert OSeMOSYS CPLEX files into different formats")
parser.add_argument("cplex_file",
help="The filepath of the OSeMOSYS cplex output file")
parser.add_argument("output_file",
help="The filepath of the converted file that will be written")
parser.add_argument("-s", "--start_year", type=int, default=2015,
help="Output only the results from this year onwards")
parser.add_argument("-e", "--end_year", type=int, default=2070,
help="Output only the results upto and including this year")
group = parser.add_mutually_exclusive_group()
group.add_argument("--csv", action="store_true",
help="Output file in comma-separated-values format")
group.add_argument("--cbc", action="store_true",
help="Output file in CBC format, (default option)")
args = parser.parse_args()
if args.csv:
output_format = 'csv'
else:
output_format = 'cbc'
convert_cplex_file(args.cplex_file, args.output_file,
args.start_year, args.end_year,
output_format)