Skip to content

Commit

Permalink
Added different methods to call GAMS based on lower level APIs.
Browse files Browse the repository at this point in the history
These APIs are more stable and their source files are now available in pypi and compatible with many platforms and py versions.
  • Loading branch information
kavvkon committed Dec 29, 2017
1 parent 2c2ed0d commit 98aa29e
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 56 deletions.
6 changes: 3 additions & 3 deletions DispaSET/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

__version__ = None
# Sets the __version__ variable
import _version
__version__ = _version.__version__
from ._version import __version__

from .preprocessing.preprocessing import get_git_revision_tag
__gitversion__ = get_git_revision_tag()
Expand Down Expand Up @@ -63,13 +62,14 @@
from .postprocessing.postprocessing import aggregate_by_fuel
from .postprocessing.postprocessing import plot_energy_country_fuel
from .postprocessing.postprocessing import plot_country_capacities
from .cli import *

# Removeing log file:
if os.path.isfile('warn.log'):
try:
os.remove('warn.log')
except:
print 'Could not erase previous log file "warn.log"'
print ('Could not erase previous log file "warn.log"')

# Setting logging configuration:
try:
Expand Down
78 changes: 78 additions & 0 deletions DispaSET/misc/gms_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import time
import logging
import sys
import os

def solve_high_level(gams_folder,sim_folder,output_lst=False):
"""Use higher level apis to run GAMSy"""
# create GAMS workspace:
from gams import GamsWorkspace
try:
ws = GamsWorkspace(system_directory=gams_folder, working_directory=sim_folder, debug=3)
t1 = ws.add_job_from_file('UCM_h.gms')
opt = ws.add_options()
# Do not create .lst file
if not output_lst:
if sys.platform == 'win32':
opt.output = 'nul'
else:
opt.output = '/dev/null'
time0 = time.time()
status = t1.run(opt)
except Exception as e:
if 'optCreateD' in str(e):
logging.error('The GAMS solver can only be run once in the same console. Please open another console')
sys.exit(1)
else:
logging.error('The following error occured when trying to solve the model in gams: ' + str(e))
sys.exit(1)
logging.info('Completed simulation in {0:.2f} seconds'.format(time.time() - time0))
return status


def solve_low_level(gams_folder,sim_folder,output_lst=False,logoption=3):
"""Use lower level apis to run GAMS. BAsed on GAMS xpexample2.py"""
from gamsxcc import new_gamsxHandle_tp, gamsxRunExecDLL, gamsxFree, gamsxCreateD, GMS_SSSIZE
from optcc import new_optHandle_tp, optReadDefinition, optSetStrStr, optSetIntStr, optHandleToPtr, optFree, \
optCreateD

model = os.path.join(sim_folder,'UCM_h.gms')

def terminate(gamsxHandle, optHandle, rc):
optFree(optHandle)
gamsxFree(gamsxHandle)
os._exit(rc)

def callGams(gamsxHandle, optHandle, sysDir, model):
deffile = sysDir + "/optgams.def"

if optReadDefinition(optHandle, deffile):
print("*** Error ReadDefinition, cannot read def file:" + deffile)
return False

optSetStrStr(optHandle, "SysDir", sysDir)
optSetStrStr(optHandle, "WorkDir", sim_folder)
optSetStrStr(optHandle, "Input", model)
optSetIntStr(optHandle, "LogOption", logoption)
ret = gamsxRunExecDLL(gamsxHandle, optHandleToPtr(optHandle), sysDir, 1)
if ret[0] != 0:
print("*** Error RunExecDLL: Error in GAMS call = " + str(ret[1]))
return False

return True

optHandle = new_optHandle_tp()
gamsxHandle = new_gamsxHandle_tp()

try:
rc = gamsxCreateD(gamsxHandle, gams_folder, GMS_SSSIZE)
rc = optCreateD(optHandle, gams_folder, GMS_SSSIZE)
time0 = time.time()
status = callGams(gamsxHandle, optHandle, gams_folder, model)
except Exception as e:
logging.error('The following error occured when trying to solve the model in gams: ' + str(e))
sys.exit(1)
finally:
terminate(gamsxHandle, optHandle, 0)
logging.info('Completed simulation in {0:.2f} seconds'.format(time.time() - time0))
return status
2 changes: 1 addition & 1 deletion DispaSET/preprocessing/preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def get_git_revision_tag():
"""Get version of DispaSET used for this run. tag + commit hash"""
from subprocess import check_output
try:
return check_output(["git", "describe"]).strip()
return check_output(["git", "describe","--tags"]).strip()
except:
return 'NA'

Expand Down
84 changes: 33 additions & 51 deletions DispaSET/solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,86 +18,67 @@
import time

from .misc.gdx_handler import get_gams_path, import_local_lib, package_exists
from .misc.gms_handler import solve_high_level, solve_low_level


def is_sim_folder_ok(sim_folder):
'''
Function that checks if the provided path is a valid Dispa-SET simulation folder
The following files are required:
- Inputs.gdx
- UCM_h.gms
:param sim_folder: path (absolute or relative) to the simulation folder
'''
if not os.path.exists(sim_folder):
logging.error('The provided DispaSET simulation environment folder (' + sim_folder + ') does not exist')
return False

if not os.path.exists(os.path.join(sim_folder, 'Inputs.gdx')):
logging.error('There is no Inputs.gdx file within the specified DispaSET simulation environment folder (' + sim_folder + '). Check that the GDX output is activated in the option file and that no error stated during the pre-processing')
logging.error(
'There is no Inputs.gdx file within the specified DispaSET simulation environment folder (' + sim_folder + '). Check that the GDX output is activated in the option file and that no error stated during the pre-processing')
return False

if not os.path.exists(os.path.join(sim_folder, 'UCM_h.gms')):
logging.error('There is no UCM_h.gms file within the specified DispaSET simulation environment folder (' + sim_folder + ')')
logging.error(
'There is no UCM_h.gms file within the specified DispaSET simulation environment folder (' + sim_folder + ')')
return False
return True


def solve_GAMS(sim_folder, gams_folder=None, work_dir=None, output_lst=False):
def solve_GAMS(sim_folder, gams_folder=None, output_lst=False):
'''
Function used to run the optimization using the GAMS engine.
Function used to run the optimization using the GAMS engine.
:param sim_folder: path to a valid Dispa-SET simulation folder
:param gams_folder: path to the gams folder. If not provided, the script will try to find it automatically
:param work_dir: path to the working directory (does not need to be provided)
:param output_lst: Set to True to conserve a copy of the GAMS lst file in the simulation folder
'''

if not package_exists('gams'):
logging.warning('Could not import gams. Trying to automatically locate gdxcc folder')
if not import_local_lib('gams'):
return False

if package_exists('gams'):
solv_func = solve_high_level
else:
logging.warning('Could not import gams. Trying to use lower level APIs')
if package_exists('gamsxcc') and package_exists('optcc'):
solv_func = solve_low_level
else:
logging.warning('Could not import lower level APIs. Trying to locate local version')
if not import_local_lib('gams'):
return False
if not os.path.exists(gams_folder):
logging.warn('The provided path for GAMS (' + gams_folder + ') does not exist. Trying to locate...')
logging.warning('The provided path for GAMS (' + gams_folder + ') does not exist. Trying to locate...')
gams_folder = get_gams_path()
if not os.path.exists(gams_folder):
logging.error('GAMS path cannot be located. Simulation is stopped')
return False
sim_folder = sim_folder.encode()
gams_folder = gams_folder.encode()
sim_folder = os.path.abspath(sim_folder).encode()
gams_folder = os.path.abspath(gams_folder).encode()

if is_sim_folder_ok(sim_folder):
# create GAMS workspace:
from gams import GamsWorkspace
try:
ws = GamsWorkspace(system_directory=gams_folder, working_directory=work_dir, debug=3)
shutil.copy(os.path.join(sim_folder, 'UCM_h.gms'), ws.working_directory)
shutil.copy(os.path.join(sim_folder, 'Inputs.gdx'), ws.working_directory)
t1 = ws.add_job_from_file('UCM_h.gms')
opt = ws.add_options()
#Do not create .lst file
if not output_lst:
if sys.platform == 'win32':
opt.output = 'nul'
else:
opt.output = '/dev/null'
time0 = time.time()
t1.run(opt)
except Exception as e:
if 'optCreateD' in str(e):
logging.error('The GAMS solver can only be run once in the same console. Please open another console')
sys.exit(1)
else:
logging.error('The following error occured when trying to solve the model in gams: ' + str(e))
sys.exit(1)
logging.info('Completed simulation in {0:.2f} seconds'.format(time.time() - time0))

# copy the result file to the simulation environment folder:
shutil.copy(os.path.join(ws.working_directory, 'Results.gdx'), sim_folder)
for filename in ['UCM_h.lst','UCM_h.log','debug.gdx']:
if os.path.isfile(os.path.join(ws.working_directory, 'debug.gdx')):
shutil.copy(os.path.join(ws.working_directory, 'debug.gdx'), sim_folder)
if os.path.isfile(os.path.join(ws.working_directory, 'debug.gdx')):
logging.warn('A debug file was created. There has probably been an optimization error')
ret = solv_func(gams_folder, sim_folder, output_lst=output_lst)
if os.path.isfile(os.path.join(sim_folder, 'debug.gdx')):
logging.warning('A debug file was created. There has probably been an optimization error')
if os.path.isfile('warn.log'):
shutil.copy('warn.log', os.path.join(sim_folder, 'warn_solve.log'))
else:
Expand All @@ -106,8 +87,8 @@ def solve_GAMS(sim_folder, gams_folder=None, work_dir=None, output_lst=False):

def solve_pyomo(sim_folder):
'''
Function used to run the optimization using the PYOMO engine.
Function used to run the optimization using the PYOMO engine.
:param sim_folder: path to a valid Dispa-SET simulation folder
'''
import pickle
Expand All @@ -119,14 +100,15 @@ def solve_pyomo(sim_folder):
LPFormulation = False
else:
LPFormulation = True

if os.path.isfile(SimData['config']['cplex_path']):
path_cplex = SimData['config']['cplex_path']
else:
path_cplex = ''
if len(SimData['config']['cplex_path']) > 2:
logging.warn('The specified path for cplex (' + SimData['config']['cplex_path'] + ') is not valid. It will be ignored')

logging.warn('The specified path for cplex (' + SimData['config'][
'cplex_path'] + ') is not valid. It will be ignored')

time0 = time.time()
results = DispaSolve(SimData['sets'], SimData['parameters'], LPFormulation=LPFormulation, path_cplex=path_cplex)
logging.info('Completed simulation in {0:.2f} seconds'.format(time.time() - time0))
Expand Down
7 changes: 6 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ def read(*parts):
"numpy >= 1.12",
"pandas >= 0.19",
"xlrd >= 0.9",
"matplotlib >= 1.5.1"
"matplotlib >= 1.5.1",
"gdxcc >= 7",
"gamsxcc",
"optcc"
],
extras_require={'pyomo': ['pyomo>=5.2'],
},
entry_points={
'console_scripts': [
'dispaset = DispaSET.cli:cli'
Expand Down

0 comments on commit 98aa29e

Please sign in to comment.