Running NEOS from Python API

Problems with syntax of GAMS
Post Reply
pitters
User
User
Posts: 13
Joined: 1 year ago

Running NEOS from Python API

Post by pitters » 8 months ago

Hi!

I'm able to run a GAMS/NEOS process through the NEOS button "RUN NEOS",
Screenshot_1.png
Screenshot_1.png (18.24 KiB) Viewed 3422 times
I would like to run this process through python api, but for obious reasons I cannot actually press the "RUN NEOS" button from python. I'm running a very basic code in python, something like this:

Code: Select all

    workdir = os.path.dirname(os.getcwd())
    ws = GamsWorkspace(workdir)
    job = ws.add_job_from_file('filename')
    job.run()

I've tried to change the solver to kestrel:

Code: Select all

option solver = kestrel
SOLVE prop MINIMIZING ZFO USING MINLP;
But I get this error:

Code: Select all

Connecting to: https://neos-server.org:3333
Traceback (most recent call last):
  File "C:\GAMS\35\gmske_nx.py", line 1049, in <module>
    kestrel.connectServer()
  File "C:\GAMS\35\gmske_nx.py", line 539, in connectServer
    reply = self.neos.ping()
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1109, in __call__
    return self.__send(self.__name, args)
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1450, in __request
    response = self.__transport.request(
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1153, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1165, in single_request
    http_conn = self.send_request(host, handler, request_body, verbose)
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1278, in send_request
    self.send_content(connection, request_body)
  File "C:\GAMS\35\GMSPython\lib\xmlrpc\client.py", line 1308, in send_content
    connection.endheaders(request_body)
  File "C:\GAMS\35\GMSPython\lib\http\client.py", line 1250, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\GAMS\35\GMSPython\lib\http\client.py", line 1010, in _send_output
    self.send(msg)
  File "C:\GAMS\35\GMSPython\lib\http\client.py", line 950, in send
    self.connect()
  File "C:\GAMS\35\GMSPython\lib\http\client.py", line 1424, in connect
    self.sock = self._context.wrap_socket(self.sock,
  File "C:\GAMS\35\GMSPython\lib\ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "C:\GAMS\35\GMSPython\lib\ssl.py", line 1040, in _create
    self.do_handshake()
  File "C:\GAMS\35\GMSPython\lib\ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:1125)
ERR: Solver rc 1 



How can I run the process with the normal green play button, but running in NEOS?

User avatar
Clemens
Posts: 55
Joined: 6 years ago

Re: Running NEOS from Python API

Post by Clemens » 8 months ago

Hi,

It seems that the Kestrel solver uses an invalid certificate. Actually it should be aware of cacert.pem located in [GAMS dir]\GMSPython\Lib\site-packages\certifi.
Does the Kestrel solver work from command line, if you do not have a Python script in between? There is also a Python example that demonstrates job submission to NEOS: [GAMS dir]\apifiles\Python\transport_neos.py

This example has been adjusted after GAMS 35 regarding finding the right/valid certificate. For your convenience, here is the latest version of this file:

Code: Select all

import os
import sys
import time
import xmlrpc.client
from gams import *

import ssl
import certifi

# NEOS XML Template (to be filled)
xml = r'''<document>
<category>:category:</category>
<solver>:solver:</solver>
<inputType>GAMS</inputType>
<email>:email:</email>
<priority>short</priority>
<model><![CDATA[:model:]]></model>
<wantgdx><![CDATA[yes]]></wantgdx>
<wantlog><![CDATA[yes]]></wantlog>
<wantlst><![CDATA[yes]]></wantlst>
</document>'''
    
if __name__ == "__main__":
    if len(sys.argv) > 1:
        ws = GamsWorkspace(system_directory = sys.argv[1])
    else:
        ws = GamsWorkspace()

    model = 'trnsport' # str | Name of the main .gms file
    ws.gamslib(model)

    ssl_context = ssl.create_default_context()
    # Explicitly point to 'certifi' *.pem file in case the OpenSSL default CA certificate path points to expired certificates
    if sys.platform == "win32":
        ssl_context.load_verify_locations(certifi.where())
    neos = xmlrpc.client.ServerProxy('https://neos-server.org:3333', context=ssl_context)
    alive = neos.ping()
    if alive != "NeosServer is alive\n":
        raise Exception('*** Could not make connection to NEOS Server')
    # can neither choose SoPlex nor CBC as LP solver on NEOS, so pretend its a MIP and use CBC
    xml = xml.replace(':category:', 'MILP')
    xml = xml.replace(':solver:', 'CBC')
    if 'NEOS_EMAIL' in os.environ:
        xml = xml.replace(':email:', os.environ['NEOS_EMAIL'])
    else:
        raise Exception("Environment variable 'NEOS_EMAIL' not found")
    with open(os.path.join(ws.working_directory, model+'.gms'), 'r') as f:
        xml = xml.replace(':model:', f.read())
    
    jobNumber, password = neos.submitJob(xml)
    print("Job number:", jobNumber)
    print("Job password:", password)
    
    if jobNumber == 0:
        raise Exception('*** NEOS Server error:' + password)
    
    offset = 0
    echo = True
    status = ''
    while status != 'Done':
        time.sleep(1)
        result, offset = neos.getIntermediateResults(jobNumber, password, offset)
        result = result.data.decode()
        if echo:
            if result.find('Composing results.') != -1: #this removes the lst output
                result = result.split('Composing results.', 1)[0]
                echo = False
            print(result, end='')
        status = neos.getJobStatus(jobNumber, password)
    
    result = neos.getFinalResults(jobNumber, password)
    with open(str(jobNumber)+'-'+os.path.splitext(os.path.basename(model+'.gms'))[0]+'.lst', 'w') as rf:
        rf.write(result.data.decode())
    result = neos.getOutputFile(jobNumber, password, 'solver-output.zip')
    with open(str(jobNumber)+'-'+'solver-output.zip', 'wb') as rf:
        rf.write(result.data)
Best,
Clemens

pitters
User
User
Posts: 13
Joined: 1 year ago

Re: Running NEOS from Python API

Post by pitters » 8 months ago

Clemens wrote:
8 months ago
Hi,

It seems that the Kestrel solver uses an invalid certificate. Actually it should be aware of cacert.pem located in [GAMS dir]\GMSPython\Lib\site-packages\certifi.
Does the Kestrel solver work from command line, if you do not have a Python script in between? There is also a Python example that demonstrates job submission to NEOS: [GAMS dir]\apifiles\Python\transport_neos.py

Hi Clemens,

Thanks for your response. The Kestrel solver is not working from GAMS, so it should not be a python script problem, as you describe, it is a certificate problem.

The file 'cacert.pem' is in the directory you point, but I dont know how to solve the invalid certificate issue.

Best,
Pitters

User avatar
Clemens
Posts: 55
Joined: 6 years ago

Re: Running NEOS from Python API

Post by Clemens » 8 months ago

I assume that the error is the same when running Kestrel from command line. So it seems that setting the SSL_CERT_FILE in [GAMS dir]\gmske_nt.cmd is not enough.

If you allow me an experiment, could you change the following line of code in [GAMS dir]\gmske_nx.py (line 537):

Code: Select all

      self.neos = xmlrpc.client.Server("%s://%s:%s" % (self.serverProtocol,self.serverHost,self.serverPort))
to:

Code: Select all

      import ssl
      import certifi
      ssl_context = ssl.create_default_context()
      if sys.platform == "win32":
        ssl_context.load_verify_locations(certifi.where())
      self.neos = xmlrpc.client.Server("%s://%s:%s" % (self.serverProtocol,self.serverHost,self.serverPort), context=ssl_context)
Let me know if this helps or if you have problems modifying the file.

Best,
Clemens

danish3186
User
User
Posts: 6
Joined: 7 months ago

Re: Running NEOS from Python API

Post by danish3186 » 6 months ago

Can we add data from excel file, model from texts and then use python to send it to NEOS ?

Code: Select all

model = 'trnsport' # str | Name of the main .gms file
    ws.gamslib(model)
The example in GAMS uses a .gms file which contains the data and model both.
I am trying to build my model from the text and get data from excel as it's huge.

Thank You!

User avatar
bussieck
Moderator
Moderator
Posts: 832
Joined: 6 years ago

Re: Running NEOS from Python API

Post by bussieck » 6 months ago

NEOS does not allow you to run external programs like gdxxrw, so do the Excel to GDX conversion locally and submit gms and gdx to NEOS.

-Michael

pitters
User
User
Posts: 13
Joined: 1 year ago

Re: Running NEOS from Python API

Post by pitters » 2 months ago

Hi @Clemens,

This change solved the problem.

Thanks a lot!

Clemens wrote:
8 months ago
I assume that the error is the same when running Kestrel from command line. So it seems that setting the SSL_CERT_FILE in [GAMS dir]\gmske_nt.cmd is not enough.

If you allow me an experiment, could you change the following line of code in [GAMS dir]\gmske_nx.py (line 537):

Code: Select all

      self.neos = xmlrpc.client.Server("%s://%s:%s" % (self.serverProtocol,self.serverHost,self.serverPort))
to:

Code: Select all

      import ssl
      import certifi
      ssl_context = ssl.create_default_context()
      if sys.platform == "win32":
        ssl_context.load_verify_locations(certifi.where())
      self.neos = xmlrpc.client.Server("%s://%s:%s" % (self.serverProtocol,self.serverHost,self.serverPort), context=ssl_context)
Let me know if this helps or if you have problems modifying the file.

Best,
Clemens

Post Reply