Repository: Pyomo/pyomo

Issue:
GAMS Solver Results Parser Exception for Objective Values Over `1E4`
## Summary
The `solve` method of the Pyomo GAMS shell solver interface may encounter an `IndexError` when parsing the `GAMS_OBJECTIVE` line of the `results.dat` file output by GAMS to obtain a final model solution. This occurs in the event that the final objective value is no less than `1E4`. Whether this exception is encountered is also contingent on the version of the GAMS executable.

### Steps to Reproduce the issue
1. Install GAMS (39.1.0 or later) according to the [GAMS documentation](https://www.gams.com/download/).
2. Invoke Pyomo GAMS solver interface on a model with optimal value not exceeding 10,000. Simple working example:
```python
import pyomo.environ as pyo

m = pyo.ConcreteModel()

m.S = pyo.Set(initialize=list(range(5)))
m.x = pyo.Var(m.S, bounds=(0, 1), initialize=1)
m.obj = pyo.Objective(expr=2000 * pyo.summation(m.x), sense=pyo.maximize)

solver = pyo.SolverFactory("gams:conopt")
res = solver.solve(m)
```

### Error Message

I encounter this exception with a GAMS 39.1.0 executable:

<!-- If Pyomo reported an error, provide the error message. PLEASE INCLUDE THE ENTIRE STACK TRACE. -->

<!-- If it did not report an error but the output appears incorrect, provide the incorrect output. If there was no error message and no output but the result is incorrect, describe how it does not match what you expect. -->
```console
Traceback (most recent call last):
  File "/home/jasherma/Documents/vim_example/test_solvers/test_gams_large_lp.py", line 23, in <module>
    res = solver.solve(
  File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/solvers/plugins/solvers/GAMS.py", line 853, in solve
    model_soln, stat_vars = self._parse_dat_results(
  File "/home/jasherma/Documents/cmu/phd-project/pyomo_repo/pyomo/pyomo/solvers/plugins/solvers/GAMS.py", line 1235, in _parse_dat_results
    model_soln[items[0]] = (items[1], items[2])
IndexError: list index out of range

```
With GAMS 35.2, I encounter no exception, and the solver successfully returns an optimal solution.

### Information on your system

Pyomo version: 6.4.3dev0 (main), with GAMS 39.1.0 executable academic license
Python version: 3.9.13
Operating system: Ubuntu 20.04
How Pyomo was installed (PyPI, conda, source): source (main branch)
Solver (if applicable): Any GAMS solver (linked with GAMS 39.1.0 and 35.2.0 executables, try other versions as necessary). Problem holds for CONOPT, IPOPT, KNITRO, CPLEX. Appears to be independent of the solver called by GAMS.


### Additional information

<!-- If you have any additional information, please list it here. -->


<!-- We encourage you to try, as much as possible, to reduce your problem to the minimal example that still reproduces the issue. That would help us a lot in fixing it quickly and effectively!

If you want to ask a question (how to use Pyomo, what it can do, etc.), please refer to our [online documentation](https://github.com/Pyomo/pyomo#getting-help) on ways to get help. -->


Interphase of Pyomo with GAMS global solvers cannot read solutions
I tried using GAMS solver, BARON, through Pyomo. I tried using a simple model just to make sure it was working as expected. However, when I run the following code,

```
from pyomo.environ import *

m = ConcreteModel()

m.x = Var([1,2])

m.obj = Objective(expr=-(m.x[1]-2)*(m.x[1]-3)*(m.x[1]-4)*(m.x[1]-6)*(-m.x[2]-1)*(m.x[2]-5), sense=maximize)

m.cons1 = Constraint(expr=m.x[1]<=10)

m.cons2 = Constraint(expr=m.x[1]>=1)

m.cons3 = Constraint(expr=m.x[2]<=7)

m.cons4 = Constraint(expr=m.x[2]>=0)

solver = SolverFactory('gams') 
solvename = 'baron'

sub_options=['GAMS_MODEL.optfile = 1;','\n',
              '$onecho > '+solvename+'.opt \n',
              '$offecho \n']

io_options = dict(
                  add_options=sub_options,
                  )

results = solver.solve(m, tee=True, solver=solvename, io_options=io_options)
```

I get this error:

```
  File C:\ProgramData\Anaconda3\lib\site-packages\pyomo\solvers\plugins\solvers\GAMS.py:1235 in _parse_dat_results
    model_soln[items[0]] = (items[1], items[2])

IndexError: list index out of range
```

GAMS still says that it reached normal completion and the solver says an optimal solution was found, but, for some reason the results cannot be loaded back.


Discussion:

I believe this is a duplicate of #2571, and is a result of recent versions of GAMS changing their output format.

Resolving patch:
diff --git a/pyomo/repn/plugins/gams_writer.py b/pyomo/repn/plugins/gams_writer.py
--- a/pyomo/repn/plugins/gams_writer.py
+++ b/pyomo/repn/plugins/gams_writer.py
@@ -798,11 +798,13 @@ def _write_model(self,
                 output_file.write("\nput results;")
                 output_file.write("\nput 'SYMBOL  :  LEVEL  :  MARGINAL' /;")
                 for var in var_list:
-                    output_file.write("\nput %s ' ' %s.l ' ' %s.m /;" % (var, var, var))
+                    output_file.write("\nput %s ' ' %s.l ' ' %s.m /;"
+                                      % (var, var, var))
                 for con in constraint_names:
-                    output_file.write("\nput %s ' ' %s.l ' ' %s.m /;" % (con, con, con))
-                output_file.write("\nput GAMS_OBJECTIVE GAMS_OBJECTIVE.l "
-                                  "GAMS_OBJECTIVE.m;\n")
+                    output_file.write("\nput %s ' ' %s.l ' ' %s.m /;"
+                                      % (con, con, con))
+                output_file.write("\nput GAMS_OBJECTIVE ' ' GAMS_OBJECTIVE.l "
+                                  "' ' GAMS_OBJECTIVE.m;\n")
 
                 statresults = put_results + 'stat.dat'
                 output_file.write("\nfile statresults /'%s'/;" % statresults)


Test patch:
diff --git a/pyomo/solvers/tests/checks/test_GAMS.py b/pyomo/solvers/tests/checks/test_GAMS.py
--- a/pyomo/solvers/tests/checks/test_GAMS.py
+++ b/pyomo/solvers/tests/checks/test_GAMS.py
@@ -9,8 +9,10 @@
 #  This software is distributed under the 3-clause BSD License.
 #  ___________________________________________________________________________
 
-
-from pyomo.environ import ConcreteModel, Var, Objective, Constraint, maximize, Expression, log10
+import pyomo.environ as pyo
+from pyomo.environ import (
+    ConcreteModel, Var, Objective, Constraint, maximize, Expression, log10,
+)
 from pyomo.opt import SolverFactory, TerminationCondition
 
 from pyomo.solvers.plugins.solvers.GAMS import (
@@ -318,6 +320,27 @@ def test_version_gms(self):
         with SolverFactory("gams", solver_io="gms") as opt:
             self.assertIsNotNone(opt.version())
 
+    @unittest.skipIf(not gamsgms_available,
+                     "The 'gams' executable is not available")
+    def test_dat_parser(self):
+        # This tests issue 2571
+        m = pyo.ConcreteModel()
+        m.S = pyo.Set(initialize=list(range(5)))
+        m.a_long_var_name = pyo.Var(m.S, bounds=(0, 1), initialize=1)
+        m.obj = pyo.Objective(
+            expr=2000 * pyo.summation(m.a_long_var_name), sense=pyo.maximize)
+        solver = pyo.SolverFactory("gams:conopt")
+        res = solver.solve(
+            m, symbolic_solver_labels=True, load_solutions=False,
+            io_options={'put_results_format': 'dat'})
+        self.assertEqual(res.solution[0].Objective['obj']['Value'], 10000)
+        for i in range(5):
+            self.assertEqual(
+                res.solution[0].Variable[f'a_long_var_name_{i}_']['Value'],
+                1
+            )
+
+
 class GAMSLogfileTestBase(unittest.TestCase):
     def setUp(self):
         """Set up model and temporary directory."""