gamspy-base 52.0.0rc1__py3-none-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gamspy_base/__init__.py +18 -0
- gamspy_base/eula.pdf +0 -0
- gamspy_base/gams +0 -0
- gamspy_base/gamscmex.out +0 -0
- gamspy_base/gamserrs.txt +1318 -0
- gamspy_base/gamsgetkey +0 -0
- gamspy_base/gamslice.txt +8 -0
- gamspy_base/gamsprobe +0 -0
- gamspy_base/gamsstmp.txt +1 -0
- gamspy_base/gdxdiff +0 -0
- gamspy_base/gdxdump +0 -0
- gamspy_base/gevopt.def +102 -0
- gamspy_base/gmscmpun.txt +56 -0
- gamspy_base/gmscvnus.run +4 -0
- gamspy_base/gmscvnux.out +0 -0
- gamspy_base/gmsgenus.run +4 -0
- gamspy_base/gmsgenux.out +0 -0
- gamspy_base/gmske_us.run +11 -0
- gamspy_base/gmske_ux.out +912 -0
- gamspy_base/gmsprmun.txt +12 -0
- gamspy_base/gmssb_us.run +4 -0
- gamspy_base/gmssb_ux.out +0 -0
- gamspy_base/libco4cclib64.dylib +0 -0
- gamspy_base/libconopt464.dylib +0 -0
- gamspy_base/libconoptlu.dylib +0 -0
- gamspy_base/libcplex2212.dylib +0 -0
- gamspy_base/libcpxcclib64.dylib +0 -0
- gamspy_base/libcrypto.3.dylib +0 -0
- gamspy_base/libcvdcclib64.dylib +0 -0
- gamspy_base/libdctmdclib64.dylib +0 -0
- gamspy_base/libgcc_s.1.1.dylib +0 -0
- gamspy_base/libgdxcclib64.dylib +0 -0
- gamspy_base/libgdxdclib64.dylib +0 -0
- gamspy_base/libgfortran.5.dylib +0 -0
- gamspy_base/libgmdcclib64.dylib +0 -0
- gamspy_base/libgmszlib164.dylib +0 -0
- gamspy_base/libgomp.1.dylib +0 -0
- gamspy_base/libgsscclib64.dylib +0 -0
- gamspy_base/libguccclib64.dylib +0 -0
- gamspy_base/libjoatdclib64.dylib +0 -0
- gamspy_base/liboptdclib64.dylib +0 -0
- gamspy_base/libpath52.dylib +0 -0
- gamspy_base/libptccclib64.dylib +0 -0
- gamspy_base/libquadmath.0.dylib +0 -0
- gamspy_base/libssl.3.dylib +0 -0
- gamspy_base/libstdc++.6.dylib +0 -0
- gamspy_base/mps2gms +0 -0
- gamspy_base/optconopt.def +351 -0
- gamspy_base/optconvert.def +126 -0
- gamspy_base/optcplex.def +880 -0
- gamspy_base/optgams.def +724 -0
- gamspy_base/optnlpec.def +69 -0
- gamspy_base/optpath.def +231 -0
- gamspy_base/optsbb.def +94 -0
- gamspy_base/version.py +1 -0
- gamspy_base-52.0.0rc1.dist-info/METADATA +65 -0
- gamspy_base-52.0.0rc1.dist-info/RECORD +60 -0
- gamspy_base-52.0.0rc1.dist-info/WHEEL +5 -0
- gamspy_base-52.0.0rc1.dist-info/top_level.txt +1 -0
- minigams-env-3.129d2d53b5/lib/python3.12/site-packages/minigams/GAMSPY_BASE_README.md +58 -0
gamspy_base/gmske_ux.out
ADDED
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
#
|
|
2
|
+
#MIT License
|
|
3
|
+
#
|
|
4
|
+
#Copyright (c) 2020 NEOS-Server
|
|
5
|
+
#
|
|
6
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
#of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
#in the Software without restriction, including without limitation the rights
|
|
9
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
#copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
#furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
#The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
#copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
#SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
|
|
25
|
+
import os
|
|
26
|
+
import linecache
|
|
27
|
+
try:
|
|
28
|
+
import zipextimporter
|
|
29
|
+
except:
|
|
30
|
+
pass
|
|
31
|
+
import re
|
|
32
|
+
import xmlrpc.client
|
|
33
|
+
import sys
|
|
34
|
+
import time
|
|
35
|
+
import socket
|
|
36
|
+
import base64
|
|
37
|
+
import gzip
|
|
38
|
+
import io
|
|
39
|
+
import xml.dom.minidom
|
|
40
|
+
import string
|
|
41
|
+
import pathlib
|
|
42
|
+
import ssl
|
|
43
|
+
import certifi
|
|
44
|
+
|
|
45
|
+
solverMap = {}
|
|
46
|
+
solverMap[ 1] = 'cbc' # lp
|
|
47
|
+
solverMap[ 2] = 'cbc' # mip
|
|
48
|
+
solverMap[ 3] = 'cbc' # rmip
|
|
49
|
+
solverMap[ 4] = 'ipopt' # nlp
|
|
50
|
+
solverMap[ 5] = 'path' # mcp
|
|
51
|
+
solverMap[ 6] = 'nlpec' # mpec
|
|
52
|
+
solverMap[ 7] = 'nlpec' # rmpec
|
|
53
|
+
solverMap[ 8] = 'path' # cns
|
|
54
|
+
solverMap[ 9] = 'ipopt' # dnlp
|
|
55
|
+
solverMap[10] = 'ipopt' # rminlp
|
|
56
|
+
solverMap[11] = 'shot' # minlp
|
|
57
|
+
solverMap[12] = 'ipopt' # qcp
|
|
58
|
+
solverMap[13] = 'shot' # miqcp
|
|
59
|
+
solverMap[14] = 'ipopt' # rmiqcp
|
|
60
|
+
solverMap[15] = 'jams' # emp
|
|
61
|
+
|
|
62
|
+
class KestrelException(Exception):
|
|
63
|
+
def __init__(self,msg):
|
|
64
|
+
Exception.__init__(self)
|
|
65
|
+
self.msg = msg
|
|
66
|
+
|
|
67
|
+
def __str__(self):
|
|
68
|
+
return repr(self.msg)
|
|
69
|
+
|
|
70
|
+
class KestrelSolverException(KestrelException):
|
|
71
|
+
def __init__(self,msg,solverlist):
|
|
72
|
+
KestrelException.__init__(self,msg)
|
|
73
|
+
self.msg += "\nCreate options file and include the following lines:\n\tkestrel_solver <solvername>\n"
|
|
74
|
+
self.msg += "\tneos_server <hostname>[:<port>]\n\n"
|
|
75
|
+
self.msg += "The following solvers are available on NEOS:\n"
|
|
76
|
+
for solver in solverlist:
|
|
77
|
+
self.msg += solver.upper() +"\n"
|
|
78
|
+
|
|
79
|
+
class KestrelGamsClient:
|
|
80
|
+
def __init__(self,argv):
|
|
81
|
+
self.argv=argv
|
|
82
|
+
self.serverProtocol="https"
|
|
83
|
+
self.serverHost="neos-server.org"
|
|
84
|
+
self.serverPort=3333
|
|
85
|
+
self.solverName=None
|
|
86
|
+
self.jobNumber=None
|
|
87
|
+
self.password=None
|
|
88
|
+
self.priority="long"
|
|
89
|
+
self.socket_timeout=0
|
|
90
|
+
self.authUsername=None
|
|
91
|
+
self.authUserPassword=None
|
|
92
|
+
|
|
93
|
+
# action-parameter is outdated
|
|
94
|
+
'''
|
|
95
|
+
if len(self.argv) >= 3:
|
|
96
|
+
self.cntrfile = self.argv[2]
|
|
97
|
+
self.action = self.argv[1].lower()
|
|
98
|
+
if self.action not in ['kill','retrieve','submit','solve']:
|
|
99
|
+
self.Usage()
|
|
100
|
+
else:
|
|
101
|
+
self.Usage()
|
|
102
|
+
'''
|
|
103
|
+
|
|
104
|
+
if len(self.argv) >= 2:
|
|
105
|
+
self.cntrfile = self.argv[1]
|
|
106
|
+
self.action = 'solve'
|
|
107
|
+
else:
|
|
108
|
+
self.Usage()
|
|
109
|
+
|
|
110
|
+
def Usage(self):
|
|
111
|
+
sys.stderr.write("\n--- Kestrel fatal error: usage\n")
|
|
112
|
+
sys.stderr.write(" gamske_ux.out <cntrfile>\n")
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
def Fatal(self, str):
|
|
116
|
+
sys.stderr.write("\n--- Kestrel fatal error: %s\n\n" % str)
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
def Error(self, str):
|
|
120
|
+
if self.logopt in [1,3,4]:
|
|
121
|
+
# Write the message to standard output
|
|
122
|
+
sys.stdout.write("\n--- Kestrel error: %s\n\n" % str)
|
|
123
|
+
|
|
124
|
+
if self.logopt in [2,4]:
|
|
125
|
+
# Append the error message to the logfile indicated
|
|
126
|
+
try:
|
|
127
|
+
f = open(self.logfilename,'a')
|
|
128
|
+
f.write("\n--- Kestrel error: %s\n\n" % str)
|
|
129
|
+
f.close()
|
|
130
|
+
except IOError as e:
|
|
131
|
+
self.Fatal("Could not append to log file %s" % self.logfilename)
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
f = open(self.statfilename,'a')
|
|
135
|
+
f.write("=1\n\n--- Kestrel error: %s\n\n=2\n" % str)
|
|
136
|
+
f.close()
|
|
137
|
+
except IOError as e:
|
|
138
|
+
self.Fatal("Could not append to status file %s\n" % self.statfilename)
|
|
139
|
+
|
|
140
|
+
sys.exit(0)
|
|
141
|
+
|
|
142
|
+
def getDefaultEmail(self):
|
|
143
|
+
if 'NEOS_EMAIL' in os.environ:
|
|
144
|
+
return os.environ['NEOS_EMAIL']
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
def parseControlFile(self):
|
|
148
|
+
"""
|
|
149
|
+
This function does the following with the cntr file
|
|
150
|
+
line 13:
|
|
151
|
+
extract isAscii, useOptions
|
|
152
|
+
|
|
153
|
+
line 18:
|
|
154
|
+
matrix file, save and change to gamsmatr.scr
|
|
155
|
+
|
|
156
|
+
line 19:
|
|
157
|
+
instruction file; save and change to gamsinst.scr
|
|
158
|
+
|
|
159
|
+
line 20:
|
|
160
|
+
set options file to 'kestrel.opt'
|
|
161
|
+
|
|
162
|
+
line 21:
|
|
163
|
+
status file; save and change to gamsstat.scr
|
|
164
|
+
|
|
165
|
+
line 22:
|
|
166
|
+
solution file; save and change to gamssolu.scr
|
|
167
|
+
|
|
168
|
+
line 23:
|
|
169
|
+
log file; save and remove absolute path
|
|
170
|
+
|
|
171
|
+
line 24:
|
|
172
|
+
dictionary file; save and change to gamsdict.scr
|
|
173
|
+
|
|
174
|
+
line 25:
|
|
175
|
+
set to '2' to write to log file
|
|
176
|
+
|
|
177
|
+
line 28-30:
|
|
178
|
+
set working,system,scratch directories to '.'
|
|
179
|
+
|
|
180
|
+
line 33,34,35:
|
|
181
|
+
remove license
|
|
182
|
+
|
|
183
|
+
line 37:
|
|
184
|
+
set parameter file
|
|
185
|
+
|
|
186
|
+
line 38:
|
|
187
|
+
read #models #solvers
|
|
188
|
+
ignore next #models + 2*#solvers with (SOLVER # # 0 ..) +
|
|
189
|
+
3*#solvers with (SOLVER # # 1 ...) lines
|
|
190
|
+
|
|
191
|
+
next two lines are more license (remove them)
|
|
192
|
+
|
|
193
|
+
set directories of remaining paths to current directory
|
|
194
|
+
(.scr, .so, sbbinfo.)
|
|
195
|
+
|
|
196
|
+
change the scratch file extension to 'scr'
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
f = open(self.cntrfile,'r')
|
|
201
|
+
lines = f.readlines()
|
|
202
|
+
f.close()
|
|
203
|
+
except IOError as e:
|
|
204
|
+
self.Fatal("Could not open control file %s" % self.cntrfile)
|
|
205
|
+
|
|
206
|
+
# extract control version number
|
|
207
|
+
self.cntver = 0
|
|
208
|
+
m = re.match(r'(\d+)',lines[0])
|
|
209
|
+
if m and m.groups():
|
|
210
|
+
self.cntver = int(m.groups()[0])
|
|
211
|
+
|
|
212
|
+
self.modeltype = int(lines[1].split()[0])
|
|
213
|
+
|
|
214
|
+
if self.cntver not in [42, 44, 46, 47, 48, 49, 50, 51, 52, 53]:
|
|
215
|
+
self.Fatal("GAMS cntr-file version 42, 44, 46, 47, 48, 49, 50, 51, 52, 53 required")
|
|
216
|
+
|
|
217
|
+
# extract isAscii, useOptions
|
|
218
|
+
m = re.match(r'(\d+)\s+(\d+)',lines[12])
|
|
219
|
+
if m and m.groups():
|
|
220
|
+
self.isAscii=m.groups()[0]
|
|
221
|
+
self.useOptions = int(m.groups()[1])
|
|
222
|
+
else:
|
|
223
|
+
self.Fatal("Line 13 of the control file is incorrect")
|
|
224
|
+
|
|
225
|
+
# is this is an MPSGE model?
|
|
226
|
+
self.isMPSGE = int(lines[15].split()[0])
|
|
227
|
+
|
|
228
|
+
# get the matrix and instruction scratch files and patch
|
|
229
|
+
self.matrfilename = lines[17].strip()
|
|
230
|
+
lines[17] = "gamsmatr.scr\n"
|
|
231
|
+
|
|
232
|
+
self.instfilename = lines[18].strip()
|
|
233
|
+
lines[18] = "gamsinst.scr\n"
|
|
234
|
+
|
|
235
|
+
# patch option file name; always use kestrel.opt
|
|
236
|
+
self.optfilename = ""
|
|
237
|
+
m = re.match(r'(.*)kestrel.*\.(.*)',lines[19])
|
|
238
|
+
if m and m.groups():
|
|
239
|
+
self.optfilename = m.groups()[0] + "kestrel." + m.groups()[1]
|
|
240
|
+
lines[19] = "kestrel.opt\n"
|
|
241
|
+
|
|
242
|
+
# get the status and solution scratch files and patch
|
|
243
|
+
self.statfilename = lines[20].strip()
|
|
244
|
+
lines[20] = "gamsstat.scr\n"
|
|
245
|
+
|
|
246
|
+
self.solufilename = lines[21].strip()
|
|
247
|
+
lines[21] = "gamssolu.scr\n"
|
|
248
|
+
|
|
249
|
+
# get the log filename and patch
|
|
250
|
+
self.logfilename = lines[22].strip()
|
|
251
|
+
lines[22] = "gamslog.scr\n"
|
|
252
|
+
|
|
253
|
+
# get the dictionary filename and patch
|
|
254
|
+
self.dictfilename = lines[23].strip()
|
|
255
|
+
lines[23] = "gamsdict.scr\n"
|
|
256
|
+
|
|
257
|
+
# get the logfile option, then make output written to logfile
|
|
258
|
+
m = re.match(r'(\d+)',lines[24])
|
|
259
|
+
if m and m.groups():
|
|
260
|
+
self.logopt = int(m.groups()[0])
|
|
261
|
+
lines[24]="2\n"
|
|
262
|
+
|
|
263
|
+
# set working, system, and scratch directories
|
|
264
|
+
self.scrdir = lines[29].strip()
|
|
265
|
+
lines[27] = lines[28] = lines[29] = '.\n'
|
|
266
|
+
|
|
267
|
+
# remove first part of license
|
|
268
|
+
lines[32] = lines[33] = lines[34] = "\n"
|
|
269
|
+
|
|
270
|
+
# patch parameter file
|
|
271
|
+
lines[36] = "gmsprmun.scr"
|
|
272
|
+
|
|
273
|
+
# downgrade the cntr-file version 53 to 52
|
|
274
|
+
if self.cntver == 53:
|
|
275
|
+
lines[0] = "52\n"
|
|
276
|
+
# remove seventh and eigth license line, license gets replaced anyway
|
|
277
|
+
del lines[-18]
|
|
278
|
+
del lines[-18]
|
|
279
|
+
self.cntver = 52
|
|
280
|
+
|
|
281
|
+
# downgrade the cntr-file version 52 to 51
|
|
282
|
+
if self.cntver == 52:
|
|
283
|
+
# We do not yet handle models with more than INT_MAX NNZ in Kestrel
|
|
284
|
+
lines[0] = "51\n"
|
|
285
|
+
# remove final line of CF (u+15, rvec[ 28] rvec[ 29]
|
|
286
|
+
lines = lines[:-1]
|
|
287
|
+
self.cntver = 51
|
|
288
|
+
|
|
289
|
+
# downgrade the cntr-file version 51 to 50
|
|
290
|
+
if self.cntver == 51:
|
|
291
|
+
# remove last number (savepoint) of this line
|
|
292
|
+
lines[13] = lines[13].rpartition(' ')[0] + "\n"
|
|
293
|
+
# 51 -> 50
|
|
294
|
+
lines[0] = "50\n"
|
|
295
|
+
self.cntver = 50
|
|
296
|
+
|
|
297
|
+
# downgrade the cntr-file version 50 to 49 // No change required since this was in the license section which does not get copied
|
|
298
|
+
if self.cntver == 50:
|
|
299
|
+
# 50 -> 49
|
|
300
|
+
lines[0] = "49\n"
|
|
301
|
+
self.cntver = 49
|
|
302
|
+
|
|
303
|
+
# downgrade the cntr-file version 49 to 48 // No change required since this was in the license section which does not get copied
|
|
304
|
+
if self.cntver == 49:
|
|
305
|
+
# 49 -> 48
|
|
306
|
+
lines[0] = "48\n"
|
|
307
|
+
self.cntver = 48
|
|
308
|
+
|
|
309
|
+
# downgrade the cntr-file version 48 to 47
|
|
310
|
+
if self.cntver == 48:
|
|
311
|
+
# 48 -> 47
|
|
312
|
+
lines[0] = "47\n"
|
|
313
|
+
self.cntver = 47
|
|
314
|
+
# remove last two numbers of this line
|
|
315
|
+
lines[13] = lines[13].rpartition(' ')[0] + "\n"
|
|
316
|
+
lines[13] = lines[13].rpartition(' ')[0] + "\n"
|
|
317
|
+
|
|
318
|
+
# downgrade the cntr-file version 47 to 46
|
|
319
|
+
if self.cntver == 47:
|
|
320
|
+
# 47 -> 46
|
|
321
|
+
lines[0] = "46\n"
|
|
322
|
+
self.cntver = 46
|
|
323
|
+
# remove line with file name
|
|
324
|
+
lines = lines[:-2]
|
|
325
|
+
lines.append("")
|
|
326
|
+
|
|
327
|
+
# downgrade the cntr-file version 46 to 42
|
|
328
|
+
# no support for threads, external funclib and guss
|
|
329
|
+
if self.cntver == 46:
|
|
330
|
+
# 46 -> 42
|
|
331
|
+
lines[0] = "42\n"
|
|
332
|
+
|
|
333
|
+
# remove last number of this line
|
|
334
|
+
lines[2] = lines[2].rpartition(' ')[0] + "\n"
|
|
335
|
+
|
|
336
|
+
# remove threads-option
|
|
337
|
+
lines[13] = lines[13].rpartition(' ')[0] + "\n"
|
|
338
|
+
|
|
339
|
+
# remove last two lines
|
|
340
|
+
lines = lines[:-2]
|
|
341
|
+
|
|
342
|
+
# treat the cntr-file now like a version 42 one
|
|
343
|
+
self.cntver = 42
|
|
344
|
+
|
|
345
|
+
# downgrade the cntr-file version 44 to 42
|
|
346
|
+
elif self.cntver == 44:
|
|
347
|
+
# 44 -> 42
|
|
348
|
+
lines[0] = "42\n"
|
|
349
|
+
|
|
350
|
+
# remove threads-option
|
|
351
|
+
lines[13] = lines[13].rpartition(' ')[0] + "\n"
|
|
352
|
+
|
|
353
|
+
# remove last line
|
|
354
|
+
lines = lines[:-1]
|
|
355
|
+
|
|
356
|
+
# treat the cntr-file now like a version 42 one
|
|
357
|
+
self.cntver = 42
|
|
358
|
+
|
|
359
|
+
if self.cntver == 42:
|
|
360
|
+
# remove second part of license
|
|
361
|
+
lines[-13] = lines[-12] = "\n"
|
|
362
|
+
|
|
363
|
+
# make everything in local directory
|
|
364
|
+
lines[-11] = 'model.scr\n'
|
|
365
|
+
lines[-6] = 'model.so\n'
|
|
366
|
+
lines[-5] = 'sbbinfo.scr\n'
|
|
367
|
+
lines[-4] = 'gamscntr.scr\n'
|
|
368
|
+
lines[-3] = './\n'
|
|
369
|
+
|
|
370
|
+
# patch scratch file extension
|
|
371
|
+
self.scrext = lines[-2].strip()
|
|
372
|
+
lines[-2] = 'scr\n'
|
|
373
|
+
|
|
374
|
+
# get the entire control file name
|
|
375
|
+
self.cntr = "".join(lines[:37]) + "".join(lines[-13:])
|
|
376
|
+
|
|
377
|
+
def writeErrorOutputFiles(self):
|
|
378
|
+
"""
|
|
379
|
+
This writes solution and status files returned when an error occurs.
|
|
380
|
+
"""
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
f = open(self.statfilename,"w")
|
|
384
|
+
f.write("""=0 Kestrel\n""")
|
|
385
|
+
f.close()
|
|
386
|
+
except IOError as e:
|
|
387
|
+
self.Error("Could not initialize status file %s\n" % self.statfilename)
|
|
388
|
+
|
|
389
|
+
try:
|
|
390
|
+
f = open(self.solufilename,"w")
|
|
391
|
+
f.write(""" 1 6.0000000000000000E+00
|
|
392
|
+
2 1.3000000000000000E+01
|
|
393
|
+
3 0.0000000000000000E+00
|
|
394
|
+
4 0.0
|
|
395
|
+
5 0.0000000000000000E+00
|
|
396
|
+
6 0.0
|
|
397
|
+
7 0.0
|
|
398
|
+
8 0.0
|
|
399
|
+
0 0.0\n""")
|
|
400
|
+
f.close()
|
|
401
|
+
|
|
402
|
+
except IOError as e:
|
|
403
|
+
self.Error("Could not open solution file %s\n" % self.solufilename)
|
|
404
|
+
|
|
405
|
+
def writeLog(self, text):
|
|
406
|
+
if self.logopt in [1,3,4]:
|
|
407
|
+
sys.stdout.write(text)
|
|
408
|
+
if self.logopt in [2,4]:
|
|
409
|
+
try:
|
|
410
|
+
f = open(self.logfilename,'a')
|
|
411
|
+
f.write(text)
|
|
412
|
+
f.close()
|
|
413
|
+
except IOError as e:
|
|
414
|
+
self.Fatal("Could not append to log file %s" % self.logfilename)
|
|
415
|
+
|
|
416
|
+
def parseOptionsFile(self):
|
|
417
|
+
if (self.useOptions == 0):
|
|
418
|
+
# raise KestrelSolverException("No options file indicated\n",self.kestrelGamsSolvers)
|
|
419
|
+
self.solverName = solverMap[self.modeltype]
|
|
420
|
+
elif os.access(self.optfilename,os.R_OK):
|
|
421
|
+
optfile = open(self.optfilename,'r')
|
|
422
|
+
self.writeLog("Reading parameter(s) from \"" + self.optfilename + "\"\n")
|
|
423
|
+
for line in optfile:
|
|
424
|
+
m = re.match(r'neos_user_password[\s=]+(\S+)',line)
|
|
425
|
+
if m:
|
|
426
|
+
self.writeLog(">> neos_user_password ******")
|
|
427
|
+
else:
|
|
428
|
+
self.writeLog(">> " + line)
|
|
429
|
+
|
|
430
|
+
m = re.match(r'kestrel_priority[\s=]+(\S+)',line)
|
|
431
|
+
if m:
|
|
432
|
+
value = m.groups()[0]
|
|
433
|
+
if value.lower()=="short":
|
|
434
|
+
self.priority = "short"
|
|
435
|
+
|
|
436
|
+
m = re.match(r'kestrel_solver[\s=]+(\S+)',line)
|
|
437
|
+
if m:
|
|
438
|
+
self.solverName = m.groups()[0]
|
|
439
|
+
|
|
440
|
+
m = re.match(r'neos_server[\s=]+(\S+)://(\S+):(\d+)',line)
|
|
441
|
+
if m:
|
|
442
|
+
self.serverProtocol = m.groups()[0]
|
|
443
|
+
self.serverHost = m.groups()[1]
|
|
444
|
+
self.serverPort = m.groups()[2]
|
|
445
|
+
|
|
446
|
+
m = re.match(r'neos_username[\s=]+(\S+)',line)
|
|
447
|
+
if m:
|
|
448
|
+
self.authUsername = m.groups()[0]
|
|
449
|
+
|
|
450
|
+
m = re.match(r'neos_user_password[\s=]+(\S+)',line)
|
|
451
|
+
if m:
|
|
452
|
+
self.authUserPassword = m.groups()[0]
|
|
453
|
+
|
|
454
|
+
elif re.match(r'neos_server[\s=]+(\S+)://(\S+)',line):
|
|
455
|
+
m = re.match(r'neos_server[\s=]+(\S+)://(\S+)',line)
|
|
456
|
+
self.serverProtocol = m.groups()[0]
|
|
457
|
+
self.serverHost = m.groups()[1]
|
|
458
|
+
|
|
459
|
+
elif re.match(r'neos_server[\s=]+(\S+):(\d+)',line):
|
|
460
|
+
m = re.match(r'neos_server[\s=]+(\S+):(\d+)',line)
|
|
461
|
+
self.serverHost = m.groups()[0]
|
|
462
|
+
self.serverPort = m.groups()[1]
|
|
463
|
+
|
|
464
|
+
else:
|
|
465
|
+
m = re.match(r'neos_server[\s=]+(\S+)',line)
|
|
466
|
+
if m:
|
|
467
|
+
self.serverHost = m.groups()[0]
|
|
468
|
+
|
|
469
|
+
m = re.match(r'kestrel_(job|jobnumber|jobNumber)[\s=]+(\d+)', line)
|
|
470
|
+
if m:
|
|
471
|
+
self.jobNumber=int(m.groups()[1])
|
|
472
|
+
|
|
473
|
+
m = re.match(r'kestrel_(pass|password)[\s=]+(\S+)', line)
|
|
474
|
+
if m:
|
|
475
|
+
self.password = m.groups()[1]
|
|
476
|
+
|
|
477
|
+
m = re.match(r'socket_timeout[\s=]+(\d+)',line)
|
|
478
|
+
if m:
|
|
479
|
+
self.socket_timeout = m.groups()[0]
|
|
480
|
+
socket.setdefaulttimeout(float(self.socket_timeout))
|
|
481
|
+
|
|
482
|
+
optfile.close()
|
|
483
|
+
self.writeLog("\nFinished reading from \"" + self.optfilename + "\"\n")
|
|
484
|
+
else:
|
|
485
|
+
raise KestrelSolverException("Could not read options file %s\n" % self.optfilename,self.kestrelGamsSolvers)
|
|
486
|
+
|
|
487
|
+
def connectServer(self):
|
|
488
|
+
if self.logopt in [1,3,4]:
|
|
489
|
+
sys.stdout.write("Connecting to: %s://%s:%s\n" % (self.serverProtocol,self.serverHost,self.serverPort))
|
|
490
|
+
if self.logopt in [2,4]:
|
|
491
|
+
# Append the message to the logfile indicated
|
|
492
|
+
try:
|
|
493
|
+
f = open(kestrel.logfilename,'a')
|
|
494
|
+
f.write("Connecting to: %s://%s:%s\n" % (self.serverProtocol,self.serverHost,self.serverPort))
|
|
495
|
+
f.close()
|
|
496
|
+
except IOError as e:
|
|
497
|
+
self.Fatal("Could not append to log file %s" % self.logfilename)
|
|
498
|
+
ssl_context = ssl.create_default_context()
|
|
499
|
+
if ssl_context.minimum_version < ssl.TLSVersion.TLSv1_2:
|
|
500
|
+
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
501
|
+
if sys.platform == "win32":
|
|
502
|
+
ssl_context.load_verify_locations(certifi.where())
|
|
503
|
+
self.neos = xmlrpc.client.Server("%s://%s:%s" % (self.serverProtocol,self.serverHost,self.serverPort), context=ssl_context)
|
|
504
|
+
|
|
505
|
+
reply = self.neos.ping()
|
|
506
|
+
if reply.find('alive') < 0:
|
|
507
|
+
raise KestrelException("Unable to contact NEOS at https://%s:%d" % \
|
|
508
|
+
(self.host, self.port))
|
|
509
|
+
|
|
510
|
+
def obtainSolvers(self):
|
|
511
|
+
# Form a list of all kestrel-gams solver available on NEOS
|
|
512
|
+
allKestrelSolvers = self.neos.listSolversInCategory("kestrel")
|
|
513
|
+
self.kestrelGamsSolvers = []
|
|
514
|
+
for s in allKestrelSolvers:
|
|
515
|
+
i = s.find(':GAMS')
|
|
516
|
+
if i > 0:
|
|
517
|
+
self.kestrelGamsSolvers.append(s[0:i])
|
|
518
|
+
|
|
519
|
+
def checkOptionsFile(self):
|
|
520
|
+
if self.solverName and (self.solverName.lower() not in [s.lower() for s in self.kestrelGamsSolvers]):
|
|
521
|
+
errmsg = "Solver '%s' not available on NEOS.\n" % self.solverName
|
|
522
|
+
raise KestrelSolverException(errmsg, self.kestrelGamsSolvers)
|
|
523
|
+
|
|
524
|
+
def formSubmission(self):
|
|
525
|
+
if not self.solverName:
|
|
526
|
+
raise KestrelSolverException("No 'kestrel_solver' option found in option file\n",self.kestrelGamsSolvers)
|
|
527
|
+
|
|
528
|
+
# Get the matrix, dictionary and instruction file
|
|
529
|
+
gamsFiles = {}
|
|
530
|
+
gamsFiles['cntr'] = io.BytesIO(self.cntr.encode())
|
|
531
|
+
|
|
532
|
+
# Need to read empinfo.dat or empinfo.scr
|
|
533
|
+
empInfoFileName = os.path.join(self.scrdir, "empinfo." + self.scrext)
|
|
534
|
+
if os.access(empInfoFileName,os.R_OK):
|
|
535
|
+
gamsFiles['empinfo'] = io.BytesIO()
|
|
536
|
+
f = open(empInfoFileName,"rb")
|
|
537
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['empinfo'])
|
|
538
|
+
zipper.write(f.read())
|
|
539
|
+
zipper.close()
|
|
540
|
+
f.close()
|
|
541
|
+
|
|
542
|
+
# Need to read scenarios
|
|
543
|
+
scenDictName = os.path.join(self.scrdir, "scenario_dict." + self.scrext)
|
|
544
|
+
if os.access(scenDictName,os.R_OK):
|
|
545
|
+
gamsFiles['scenario'] = io.BytesIO()
|
|
546
|
+
f = open(scenDictName,"rb")
|
|
547
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['scenario'])
|
|
548
|
+
zipper.write(f.read())
|
|
549
|
+
zipper.close()
|
|
550
|
+
f.close()
|
|
551
|
+
|
|
552
|
+
if os.access(self.matrfilename,os.R_OK):
|
|
553
|
+
gamsFiles['matr'] = io.BytesIO()
|
|
554
|
+
f = open(self.matrfilename,"rb")
|
|
555
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['matr'])
|
|
556
|
+
zipper.write(f.read())
|
|
557
|
+
zipper.close()
|
|
558
|
+
f.close()
|
|
559
|
+
|
|
560
|
+
if os.access(self.instfilename,os.R_OK):
|
|
561
|
+
gamsFiles['inst'] = io.BytesIO()
|
|
562
|
+
f = open(self.instfilename,"rb")
|
|
563
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['inst'])
|
|
564
|
+
zipper.write(f.read())
|
|
565
|
+
zipper.close()
|
|
566
|
+
f.close()
|
|
567
|
+
|
|
568
|
+
if os.access(self.dictfilename,os.R_OK):
|
|
569
|
+
gamsFiles['dict'] = io.BytesIO()
|
|
570
|
+
f = open(self.dictfilename,"rb")
|
|
571
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['dict'])
|
|
572
|
+
zipper.write(f.read())
|
|
573
|
+
zipper.close()
|
|
574
|
+
f.close()
|
|
575
|
+
|
|
576
|
+
if self.isMPSGE != 0 and self.modeltype == 5 and os.access(os.path.join(self.scrdir,'gedata.' + self.scrext),os.R_OK): # MCP might be an MPSGE model
|
|
577
|
+
gamsFiles['cge'] = io.BytesIO()
|
|
578
|
+
f = open(os.path.join(self.scrdir,'gedata.' + self.scrext),"rb")
|
|
579
|
+
zipper = gzip.GzipFile(mode='wb',fileobj=gamsFiles['cge'])
|
|
580
|
+
s=f.read()
|
|
581
|
+
end = s.find(b"gamsdict.")
|
|
582
|
+
if end != -1:
|
|
583
|
+
start = end
|
|
584
|
+
while ord(s[end]) != 32: #whitespace
|
|
585
|
+
end = end+1
|
|
586
|
+
while ord(s[start]) != 0:
|
|
587
|
+
start = start-1
|
|
588
|
+
orgStr = s[start+1:end]
|
|
589
|
+
replStr = b"./gamsdict.scr" + b" "*(len(orgStr) - len("./gamsdict.scr"))
|
|
590
|
+
s = s.replace(orgStr, replStr)
|
|
591
|
+
zipper.write(s)
|
|
592
|
+
zipper.close()
|
|
593
|
+
f.close()
|
|
594
|
+
|
|
595
|
+
self.xml = """
|
|
596
|
+
<document>
|
|
597
|
+
<category>kestrel</category>
|
|
598
|
+
<solver>%s</solver>
|
|
599
|
+
<inputType>GAMS</inputType>
|
|
600
|
+
<priority>%s</priority>
|
|
601
|
+
""" % (self.solverName,self.priority)
|
|
602
|
+
|
|
603
|
+
for key in list(gamsFiles.keys()):
|
|
604
|
+
self.xml += "<%s><base64>%s</base64></%s>\n" % (key,base64.b64encode(gamsFiles[key].getvalue()).decode(),key)
|
|
605
|
+
gamsFiles[key].close()
|
|
606
|
+
|
|
607
|
+
# Remove 'kestrel', 'neos' and 'socket_timeout' options from options file; they are not needed
|
|
608
|
+
email = None
|
|
609
|
+
xpressemail = None
|
|
610
|
+
runningtime = None
|
|
611
|
+
self.xml += "<options><![CDATA["
|
|
612
|
+
if self.useOptions:
|
|
613
|
+
with open(self.optfilename) as fp:
|
|
614
|
+
for line in fp.readlines():
|
|
615
|
+
if not re.match(r'kestrel|neos_server|neos_username|neos_user_password|email|xpressemail|runtime|socket_timeout',line):
|
|
616
|
+
self.xml += line
|
|
617
|
+
elif re.match(r'email',line):
|
|
618
|
+
email = line.rsplit()[1]
|
|
619
|
+
elif re.match(r'xpressemail',line):
|
|
620
|
+
xpressemail = line.rsplit()[1]
|
|
621
|
+
elif re.match(r'runtime',line):
|
|
622
|
+
runningtime = line.rsplit()[1]
|
|
623
|
+
self.xml += "]]></options>\n"
|
|
624
|
+
|
|
625
|
+
if not email:
|
|
626
|
+
email = self.getDefaultEmail()
|
|
627
|
+
if not email:
|
|
628
|
+
self.Error("No email address provided. Either specify it in an option file or set environment variable NEOS_EMAIL (e.g. via gamsconfig.yaml).")
|
|
629
|
+
self.xml += "<email>"
|
|
630
|
+
self.xml += email
|
|
631
|
+
self.xml += "</email>\n"
|
|
632
|
+
|
|
633
|
+
if xpressemail:
|
|
634
|
+
self.xml += "<xpressemail>"
|
|
635
|
+
self.xml += xpressemail
|
|
636
|
+
self.xml += "</xpressemail>\n"
|
|
637
|
+
|
|
638
|
+
if runningtime:
|
|
639
|
+
self.xml += "<priority>"
|
|
640
|
+
self.xml += runningtime
|
|
641
|
+
self.xml += "</priority>"
|
|
642
|
+
|
|
643
|
+
self.xml += "</document>"
|
|
644
|
+
|
|
645
|
+
def submit(self):
|
|
646
|
+
user = "%s on %s" % (os.getenv('LOGNAME'),
|
|
647
|
+
socket.getfqdn(socket.gethostname()))
|
|
648
|
+
if self.authUsername is None or self.authUserPassword is None:
|
|
649
|
+
if self.authUsername: self.writeLog("\nWarning: 'neos_username' was specified, but not 'neos_user_password'")
|
|
650
|
+
if self.authUserPassword: self.writeLog("\nWarning: 'neos_user_password' was specified, but not 'neos_username'")
|
|
651
|
+
(self.jobNumber,self.password) = \
|
|
652
|
+
self.neos.submitJob(self.xml,user,"kestrel")
|
|
653
|
+
else:
|
|
654
|
+
(self.jobNumber,self.password) = \
|
|
655
|
+
self.neos.authenticatedSubmitJob(self.xml,self.authUsername,self.authUserPassword,"kestrel")
|
|
656
|
+
if self.jobNumber==0:
|
|
657
|
+
raise KestrelException(self.password)
|
|
658
|
+
|
|
659
|
+
if self.logopt in [1,3,4]:
|
|
660
|
+
# Send the output to the screen
|
|
661
|
+
sys.stdout.write("\nNEOS job#=%d, pass=%s\n\n" % (self.jobNumber,self.password))
|
|
662
|
+
sys.stdout.write("Check the following URL for progress report :\n")
|
|
663
|
+
#sys.stdout.write("http://www-neos.mcs.anl.gov/cgi-bin/nph-neos-solver.cgi?admin=results&jobnumber=%d&pass=%s\n\n" % (self.jobNumber,self.password))
|
|
664
|
+
sys.stdout.write("%s://%s/neos/cgi-bin/nph-neos-solver.cgi?admin=results&jobnumber=%d&pass=%s\n\n" % (self.serverProtocol,self.serverHost,self.jobNumber,self.password))
|
|
665
|
+
if self.logopt in [2,4]:
|
|
666
|
+
# Append the error message to the logfile indicated
|
|
667
|
+
try:
|
|
668
|
+
f = open(self.logfilename,'a')
|
|
669
|
+
f.write("\nNEOS job#=%d, pass=%s\n\n" % (self.jobNumber,self.password))
|
|
670
|
+
f.write("Check the following URL for progress report :\n")
|
|
671
|
+
f.write("%s://%s/neos/cgi-bin/nph-neos-solver.cgi?admin=results&jobnumber=%d&pass=%s\n\n" % (self.serverProtocol,self.serverHost,self.jobNumber,self.password))
|
|
672
|
+
f.close()
|
|
673
|
+
except IOError as e:
|
|
674
|
+
self.Error("Could not append to log file %s" % self.logfilename)
|
|
675
|
+
|
|
676
|
+
try:
|
|
677
|
+
f = open(self.statfilename,'a')
|
|
678
|
+
f.write("=1\n\n")
|
|
679
|
+
f.write("\nNEOS job#=%d, pass=%s\n\n" % (self.jobNumber,self.password))
|
|
680
|
+
f.write("Check the following URL for progress report :\n")
|
|
681
|
+
f.write("%s://%s/neos/cgi-bin/nph-neos-solver.cgi?admin=results&jobnumber=%d&pass=%s\n\n" % (self.serverProtocol,self.serverHost,self.jobNumber,self.password))
|
|
682
|
+
f.write("=2\n")
|
|
683
|
+
f.close()
|
|
684
|
+
except IOError as e:
|
|
685
|
+
self.Error("Could not append to status file %s\n" % self.statfilename)
|
|
686
|
+
|
|
687
|
+
def getText(self,node):
|
|
688
|
+
"""
|
|
689
|
+
Returns the text from the node of an xml document
|
|
690
|
+
"""
|
|
691
|
+
s = ""
|
|
692
|
+
if isinstance(node,str):
|
|
693
|
+
return node
|
|
694
|
+
if isinstance(node.nodeValue,str):
|
|
695
|
+
return node.data
|
|
696
|
+
elif node.hasChildNodes():
|
|
697
|
+
for n in node.childNodes:
|
|
698
|
+
s += self.getText(n)
|
|
699
|
+
return s
|
|
700
|
+
|
|
701
|
+
def parseSolution(self,xmlstring):
|
|
702
|
+
doc = xml.dom.minidom.parseString(xmlstring)
|
|
703
|
+
for tag in ['allsolutions', 'scenrep']:
|
|
704
|
+
xmltag = tag[:4]
|
|
705
|
+
node = doc.getElementsByTagName(xmltag)
|
|
706
|
+
if node and len(node):
|
|
707
|
+
try:
|
|
708
|
+
f = open(os.path.join(self.scrdir, f"{tag}.{self.scrext}"), 'wb')
|
|
709
|
+
f.write(bytes.fromhex(self.getText(node[0])))
|
|
710
|
+
f.close()
|
|
711
|
+
except IOError as e:
|
|
712
|
+
self.Error("Could not write file %s.%s\n" % (tag, self.scrext))
|
|
713
|
+
node = doc.getElementsByTagName('solu')
|
|
714
|
+
if node and len(node):
|
|
715
|
+
try:
|
|
716
|
+
f = open(self.solufilename,'w')
|
|
717
|
+
f.write(self.getText(node[0]))
|
|
718
|
+
f.close()
|
|
719
|
+
except IOError as e:
|
|
720
|
+
self.Error("Could not write solution file %s\n" % self.solufilename)
|
|
721
|
+
|
|
722
|
+
node = doc.getElementsByTagName('stat')
|
|
723
|
+
if node and len(node):
|
|
724
|
+
try:
|
|
725
|
+
f = open(self.statfilename,'w',errors='replace')
|
|
726
|
+
f.write(self.getText(node[0]))
|
|
727
|
+
f.close()
|
|
728
|
+
except IOError as e:
|
|
729
|
+
self.Error("Could not write status file %s\n" % self.statfilename)
|
|
730
|
+
|
|
731
|
+
node = doc.getElementsByTagName('log')
|
|
732
|
+
if node and len(node):
|
|
733
|
+
if self.logopt in [1,3,4]:
|
|
734
|
+
# Send the output to the screen
|
|
735
|
+
encoding = sys.stdout.encoding
|
|
736
|
+
encoded_text = self.getText(node[0]).encode(encoding,errors='replace').decode(encoding)
|
|
737
|
+
sys.stdout.write(encoded_text)
|
|
738
|
+
if self.logopt in [2,4]:
|
|
739
|
+
# Append the error message to the logfile indicated
|
|
740
|
+
try:
|
|
741
|
+
f = open(self.logfilename,'a',errors='replace')
|
|
742
|
+
f.write(self.getText(node[0]))
|
|
743
|
+
f.close()
|
|
744
|
+
except IOError as e:
|
|
745
|
+
self.Error("Could not append log file %s\n" % self.logfilename)
|
|
746
|
+
|
|
747
|
+
doc.unlink()
|
|
748
|
+
|
|
749
|
+
def getResults(self):
|
|
750
|
+
offset = 0
|
|
751
|
+
status = self.neos.getJobStatus(self.jobNumber,self.password)
|
|
752
|
+
try:
|
|
753
|
+
while (status == "Waiting" or status=="Running"):
|
|
754
|
+
(results,offset) = self.neos.getIntermediateResults(self.jobNumber, self.password,offset)
|
|
755
|
+
if isinstance(results,xmlrpc.client.Binary):
|
|
756
|
+
results = results.data.decode()
|
|
757
|
+
if results and len(results):
|
|
758
|
+
|
|
759
|
+
if self.logopt in [1,3,4]:
|
|
760
|
+
# Send the output to the screen
|
|
761
|
+
sys.stdout.write(results)
|
|
762
|
+
if self.logopt in [2,4]:
|
|
763
|
+
# Append the error message to the logfile indicated
|
|
764
|
+
try:
|
|
765
|
+
f = open(self.logfilename,'a')
|
|
766
|
+
f.write(results)
|
|
767
|
+
f.close()
|
|
768
|
+
except IOError as e:
|
|
769
|
+
self.Error("Could not append to log file %s" % self.logfilename)
|
|
770
|
+
|
|
771
|
+
try:
|
|
772
|
+
f = open(self.statfilename,'a')
|
|
773
|
+
f.write("=1\n\n")
|
|
774
|
+
f.write(results)
|
|
775
|
+
f.write("=2\n")
|
|
776
|
+
f.close()
|
|
777
|
+
except IOError as e:
|
|
778
|
+
self.Error("Could not append to status file %s\n" % self.statfilename)
|
|
779
|
+
status = self.neos.getJobStatus(self.jobNumber,self.password)
|
|
780
|
+
time.sleep(5)
|
|
781
|
+
|
|
782
|
+
except KeyboardInterrupt as e:
|
|
783
|
+
msg = '''Keyboard Interrupt\n\
|
|
784
|
+
Job is still running on remote machine\n\
|
|
785
|
+
To retrieve results, run GAMS using solver 'kestrel' with option file:\n\
|
|
786
|
+
kestrel_job %d\n\
|
|
787
|
+
kestrel_pass %s\n\n\
|
|
788
|
+
To stop job, run GAMS using solver 'kestrelkil' with above option file\n\
|
|
789
|
+
''' % (self.jobNumber, self.password)
|
|
790
|
+
self.Error(msg)
|
|
791
|
+
|
|
792
|
+
resultsXML = self.neos.getFinalResults(self.jobNumber,self.password)
|
|
793
|
+
if isinstance(resultsXML,xmlrpc.client.Binary):
|
|
794
|
+
resultsXML = resultsXML.data
|
|
795
|
+
self.parseSolution(resultsXML)
|
|
796
|
+
|
|
797
|
+
if __name__=="__main__":
|
|
798
|
+
# print 'in gmske_ux.out'
|
|
799
|
+
# Initialization phase
|
|
800
|
+
|
|
801
|
+
try:
|
|
802
|
+
kestrel = KestrelGamsClient(sys.argv)
|
|
803
|
+
kestrel.parseControlFile()
|
|
804
|
+
try:
|
|
805
|
+
f = open(os.path.join(pathlib.Path(__file__).parent.absolute(),'gamsstmp.txt'),'r')
|
|
806
|
+
auditLine = f.readline()
|
|
807
|
+
f.close()
|
|
808
|
+
kestrel.writeLog('NEOS Kestrel ' + auditLine)
|
|
809
|
+
except:
|
|
810
|
+
pass
|
|
811
|
+
kestrel.writeLog('\nFor terms of use please inspect https://neos-server.org/neos/termofuse.html\n\n')
|
|
812
|
+
kestrel.writeErrorOutputFiles()
|
|
813
|
+
kestrel.parseOptionsFile()
|
|
814
|
+
kestrel.connectServer()
|
|
815
|
+
kestrel.obtainSolvers()
|
|
816
|
+
except KestrelException as e:
|
|
817
|
+
kestrel.Error(e.msg)
|
|
818
|
+
|
|
819
|
+
if kestrel.action=="solve":
|
|
820
|
+
# Solve with job number and password retrieves the results
|
|
821
|
+
# Otherwise we obtain them from the submission
|
|
822
|
+
|
|
823
|
+
try:
|
|
824
|
+
kestrel.parseOptionsFile()
|
|
825
|
+
kestrel.writeLog("NEOS Solver: %s\n" % kestrel.solverName)
|
|
826
|
+
if (not kestrel.jobNumber) or (not kestrel.password):
|
|
827
|
+
kestrel.checkOptionsFile()
|
|
828
|
+
kestrel.formSubmission()
|
|
829
|
+
kestrel.submit()
|
|
830
|
+
kestrel.getResults()
|
|
831
|
+
except KestrelException as e:
|
|
832
|
+
kestrel.Error(e.msg)
|
|
833
|
+
|
|
834
|
+
elif kestrel.action=="submit":
|
|
835
|
+
try:
|
|
836
|
+
kestrel.parseOptionsFile()
|
|
837
|
+
kestrel.checkOptionsFile()
|
|
838
|
+
kestrel.formSubmission()
|
|
839
|
+
kestrel.submit()
|
|
840
|
+
|
|
841
|
+
fname = os.path.join(kestrel.scrdir, "kestrel." + kestrel.scrext)
|
|
842
|
+
try:
|
|
843
|
+
f = open(fname,'a')
|
|
844
|
+
f.write("%d %s\n" % (kestrel.jobNumber, kestrel.password))
|
|
845
|
+
f.close()
|
|
846
|
+
except IOError as e:
|
|
847
|
+
kestrel.Error("Could not append to submission file %s\n" % fname)
|
|
848
|
+
|
|
849
|
+
except KestrelException as e:
|
|
850
|
+
kestrel.Error(e.msg)
|
|
851
|
+
|
|
852
|
+
elif kestrel.action=="retrieve":
|
|
853
|
+
fname = os.path.join(kestrel.scrdir, "kestrel." + kestrel.scrext)
|
|
854
|
+
|
|
855
|
+
try:
|
|
856
|
+
f = open(fname,'r')
|
|
857
|
+
except IOError as e:
|
|
858
|
+
kestrel.Error("Could not open submission file %s\n" % fname)
|
|
859
|
+
|
|
860
|
+
m = re.match(r'(\d+) ([a-zA-Z]+)',f.readline())
|
|
861
|
+
if m:
|
|
862
|
+
kestrel.jobNumber = int(m.groups()[0])
|
|
863
|
+
kestrel.password = m.groups()[1]
|
|
864
|
+
rest = f.read()
|
|
865
|
+
f.close()
|
|
866
|
+
|
|
867
|
+
if kestrel.jobNumber and kestrel.password:
|
|
868
|
+
try:
|
|
869
|
+
kestrel.getResults()
|
|
870
|
+
except KestrelException as e:
|
|
871
|
+
kestrel.Error(e.msg)
|
|
872
|
+
else:
|
|
873
|
+
kestrel.Error( "Corrupt submission file %s\n" % fname)
|
|
874
|
+
|
|
875
|
+
if (rest):
|
|
876
|
+
try:
|
|
877
|
+
f = open(fname,'w')
|
|
878
|
+
f.write(rest);
|
|
879
|
+
f.close()
|
|
880
|
+
except IOError as e:
|
|
881
|
+
kestrel.Error("Could not rewrite submission file %s\n" % fname)
|
|
882
|
+
else:
|
|
883
|
+
os.unlink(fname)
|
|
884
|
+
|
|
885
|
+
elif kestrel.action=="kill":
|
|
886
|
+
# Kill and job retrieval do not require a valid solver
|
|
887
|
+
kestrel.parseOptionsFile()
|
|
888
|
+
if kestrel.jobNumber and kestrel.password:
|
|
889
|
+
response = kestrel.neos.killJob(kestrel.jobNumber,kestrel.password)
|
|
890
|
+
|
|
891
|
+
if kestrel.logopt in [1,3,4]:
|
|
892
|
+
# Send the output to the screen
|
|
893
|
+
sys.stdout.write("\n%s\n\n" % response)
|
|
894
|
+
elif (kestrel.logopt == 2):
|
|
895
|
+
# Append the error message to the logfile indicated
|
|
896
|
+
try:
|
|
897
|
+
f = open(kestrel.logfilename,'a')
|
|
898
|
+
f.write("\n%s\n\n" % response)
|
|
899
|
+
f.close()
|
|
900
|
+
except IOError as e:
|
|
901
|
+
kestrel.Error("Could not append to log file %s" % kestrel.logfilename)
|
|
902
|
+
|
|
903
|
+
try:
|
|
904
|
+
f = open(kestrel.statfilename,'a')
|
|
905
|
+
f.write("=1\n\n")
|
|
906
|
+
f.write("%s\n\n" % response)
|
|
907
|
+
f.write("=2\n")
|
|
908
|
+
f.close()
|
|
909
|
+
except IOError as e:
|
|
910
|
+
kestrel.Error("Could not append to status file %s\n" % kestrel.statfilename)
|
|
911
|
+
else:
|
|
912
|
+
kestrel.Error( "No 'kestrel_job' and 'kestrel_pass' options found in %s\n\n" % kestrel.optfilename)
|