Repository: Pyomo/pyomo

Issue:
Pynumero Recently Stopped Working with External Functions
## Summary

Pynumero seems to have stopped working with external functions in the latest Pyomo.  It worked until very recently.  I suspect something probably broke in setting "AMPL_FUNC"

### Steps to reproduce the issue

I assume there is an external function that can be used for testing.  If not, I added one in PR #1904. 

If you have IDAES installed this will do it:

```python
from idaes.core.util.functions import functions_lib
from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP
import pyomo.environ as pyo

if __name__ == "__main__":
    m = pyo.ConcreteModel()
    flib = functions_lib()
    m.cbrt = pyo.ExternalFunction(library=flib, function="cbrt")

    m.x = pyo.Var([1, 2, 3], initialize=4.0)
    m.c = pyo.Constraint(expr=m.x[3] ** 2 + m.cbrt(m.x[1]) == 25)
    m.d = pyo.Constraint(expr=m.x[2] ** 2 + m.x[1] <= 18.0)
    m.o = pyo.Objective(expr=m.x[1] ** 4 - 3 * m.x[1] * m.x[2] ** 3 + m.x[3] ** 2 - 8.0)
    m.x[1].setlb(0.0)
    m.x[2].setlb(0.0)

    nlp = PyomoNLP(m)
    f = nlp.evaluate_objective()
    assert f == pytest.approx(-504.0)

    jac = nlp.evaluate_jacobian().toarray()
    print(jac)
``` 

### Error Message

```
WARNING: The current pynumero_ASL library is version=2, but found version=1.
    Please recompile / update your pynumero_ASL library.
function cbrt not available  <--- this is the problem
```

### Information on your system

Pyomo
    Version: 6.1.3.dev0

Python
    Version: 3.9.4 (default, Apr  9 2021, 11:43:21) [MSC v.1916 64 bit (AMD64)]
    Executable: C:\Users\EslickJ\miniconda3\envs\idaes-pse\python.exe

OS
    Platform: Windows
    Release: 10
    Version: 10.0.19041



### 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. -->




Discussion:
Setting AMPLFUNC before running pyomo does not seem to fix the issue.  The external function is still not found. 
If you rebuild the `pynumero_ASL` library, does that fix the issue?
@jsiirola, I just tried this on a different computer and it worked fine.  I also just rebuilt pynumero.  I noticed on the other computer I didn't get the warning about pynumero being out of date.  I'm now about 90% sure either I did something stupid at some point or Windows just randomly decided to start acting weird.  I'm going to try to figure out if I somehow have an old Pynumero hanging around somewhere else.  I think I may have accident;y built it with Pyomo's system at some point and left it hanging around.    
@eslickj I could reproduce your error with Pyomo's main branch, so it's not just you. I may also have an old `pynumero_ASL` library though, and haven't tried rebuilding, so this doesn't narrow it down much.
I was able to see the same problem when I was running with the old `pynumero_ASL` library.  I'm not entirely sure why, though.  #2114 may not be as backward compatible as I had hoped... digging now...

Resolving patch:
diff --git a/pyomo/contrib/pynumero/asl.py b/pyomo/contrib/pynumero/asl.py
--- a/pyomo/contrib/pynumero/asl.py
+++ b/pyomo/contrib/pynumero/asl.py
@@ -223,7 +223,7 @@ def __init__(self, filename=None, nl_buffer=None):
         # the ASL.  This should prevent it from potentially caching an
         # AMPLFUNC from the initial load and letting it bleed into
         # (potentially unrelated) subsequent instances
-        b_amplfunc = os.environ.pop('AMPLFUNC', '').encode('utf-8')
+        amplfunc = os.environ.pop('AMPLFUNC', '')
 
         if AmplInterface.ASLib is None:
             AmplInterface.ASLib, AmplInterface.interface_version \
@@ -235,8 +235,15 @@ def __init__(self, filename=None, nl_buffer=None):
 
             b_data = filename.encode('utf-8')
             if self.interface_version >= 2:
-                args = (b_data, b_amplfunc)
+                args = (b_data, amplfunc.encode('utf-8'))
             else:
+                # Old ASL interface library.
+                if amplfunc:
+                    # we need to put AMPLFUNC back into the environment,
+                    # as old versions of the library rely on ONLY the
+                    # environment variable for passing the library(ies)
+                    # locations to the ASL
+                    os.environ['AMPLFUNC'] = amplfunc
                 args = (b_data,)
             self._obj = self.ASLib.EXTERNAL_AmplInterface_new_file(*args)
         elif nl_buffer is not None:


Test patch: