We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
assert_units_consistent fails when model has reference to unindexed Var
## Summary

Running `assert_units_consistent` on a model with a `Reference` to an unindexed variable results in an error.

### Steps to reproduce the issue

```console
import pyomo.environ as pyo
from pyomo.util.check_units import assert_units_consistent

m = pyo.ConcreteModel()

m.x = pyo.Var(initialize=1, units=pyo.units.m)
m.y = pyo.Var(initialize=1, units=pyo.units.m)
m.z = pyo.Reference(m.x)
m.expr = pyo.Expression(expr=(m.x+m.z[None]))
assert_units_consistent(m)
```

### Error Message

>   Traceback (most recent call last):
> 
>   File ~\Work\assert_units_consistent_fail.py:10 in <module>
>     assert_units_consistent(m)
> 
>   File ~\miniconda3\envs\idaes-new\lib\site-packages\pyomo\util\check_units.py:236 in assert_units_consistent
>     handler(obj)
> 
>   File ~\miniconda3\envs\idaes-new\lib\site-packages\pyomo\util\check_units.py:164 in _assert_units_consistent_block
>     assert_units_consistent(component)
> 
>   File ~\miniconda3\envs\idaes-new\lib\site-packages\pyomo\util\check_units.py:219 in assert_units_consistent
>     raise TypeError("Units checking not supported for object of type {}.".format(obj.ctype))
> 
> TypeError: Units checking not supported for object of type <class 'pyomo.core.base.set.SetOf'>.

### Information on your system

Pyomo version: 6.4.0
Python version: 3.9
Operating system: Windows 11
How Pyomo was installed: Through IDAES install (I think the script uses pip?)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyomo/util/check_units.py`
Content:
```
1 #  ___________________________________________________________________________
2 #
3 #  Pyomo: Python Optimization Modeling Objects
4 #  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
5 #  Under the terms of Contract DE-NA0003525 with National Technology and
6 #  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
7 #  rights in this software.
8 #  This software is distributed under the 3-clause BSD License.
9 #  __________________________________________________________________________
10 #
11 #
12 """ Pyomo Units Checking Module
13 This module has some helpful methods to support checking units on Pyomo
14 module objects.
15 """
16 from pyomo.core.base.units_container import units, UnitsError
17 from pyomo.core.base import (Objective, Constraint, Var, Param,
18                              Suffix, Set, RangeSet, Block,
19                              ExternalFunction, Expression,
20                              value, BooleanVar)
21 from pyomo.dae import ContinuousSet, DerivativeVar
22 from pyomo.network import Port, Arc
23 from pyomo.mpec import Complementarity
24 from pyomo.gdp import Disjunct, Disjunction
25 from pyomo.core.expr.template_expr import IndexTemplate
26 from pyomo.core.expr.numvalue import native_types
27 from pyomo.util.components import iter_component
28 
29 def check_units_equivalent(*args):
30     """
31     Returns True if the units associated with each of the
32     expressions passed as arguments are all equivalent (and False
33     otherwise).
34 
35     Note that this method will raise an exception if the units are
36     inconsistent within an expression (since the units for that
37     expression are not valid).
38 
39     Parameters
40     ----------
41     args : an argument list of Pyomo expressions
42 
43     Returns
44     -------
45     bool : True if all the expressions passed as argments have the same units
46     """
47     try:
48         assert_units_equivalent(*args)
49         return True
50     except UnitsError:
51         return False
52 
53 def assert_units_equivalent(*args):
54     """
55     Raise an exception if the units are inconsistent within an
56     expression, or not equivalent across all the passed
57     expressions.
58 
59     Parameters
60     ----------
61     args : an argument list of Pyomo expressions
62         The Pyomo expressions to test
63 
64     Raises
65     ------
66     :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`
67     """
68     # this call will raise an exception if an inconsistency is found
69     pint_units = [units._get_pint_units(arg) for arg in args]
70     pint_unit_compare = pint_units[0]
71     for pint_unit in pint_units:
72         if not units._equivalent_pint_units(pint_unit_compare, pint_unit):
73             raise UnitsError(
74                 "Units between {} and {} are not consistent.".format(
75                     str(pint_unit_compare), str(pint_unit)))
76 
77 def _assert_units_consistent_constraint_data(condata):
78     """
79     Raise an exception if the any units in lower, body, upper on a
80     ConstraintData object are not consistent or are not equivalent
81     with each other.
82     """
83     # Pyomo can rearrange expressions, resulting in a value
84     # of 0 for upper or lower that does not have units associated
85     # Therefore, if the lower and/or upper is 0, we allow it to be unitless
86     # and check the consistency of the body only
87     args = list()
88     if condata.lower is not None and value(condata.lower) != 0.0:
89         args.append(condata.lower)
90 
91     args.append(condata.body)
92 
93     if condata.upper is not None and value(condata.upper) != 0.0:
94         args.append(condata.upper)
95 
96     if len(args) == 1:
97         assert_units_consistent(*args)
98     else:
99         assert_units_equivalent(*args)
100 
101 def _assert_units_consistent_arc_data(arcdata):
102     """
103     Raise an exception if the any units do not match for the connected ports
104     """
105     sport = arcdata.source
106     dport = arcdata.destination
107     if sport is None or dport is None:
108         # nothing to check
109         return
110 
111     # both sport and dport are not None
112     # iterate over the vars in one and check against the other
113     for key in sport.vars:
114         svar = sport.vars[key]
115         dvar = dport.vars[key]
116 
117         if svar.is_indexed():
118             for k in svar:
119                 svardata = svar[k]
120                 dvardata = dvar[k]
121                 assert_units_equivalent(svardata, dvardata)
122         else:
123             assert_units_equivalent(svar, dvar)
124 
125 def _assert_units_consistent_property_expr(obj):
126     """
127     Check the .expr property of the object and raise
128     an exception if the units are not consistent
129     """
130     _assert_units_consistent_expression(obj.expr)
131 
132 def _assert_units_consistent_expression(expr):
133     """
134     Raise an exception if any units in expr are inconsistent.
135     """
136     # this will raise an exception if the units are not consistent
137     # in the expression
138     pint_unit = units._get_pint_units(expr)
139     # pyomo_unit = units.get_units(expr)
140 
141 # Complementarities that are not in standard form do not
142 # current work with the checking code. The Units container
143 # should be modified to allow sum and relationals with zero
144 # terms (e.g., unitless). Then this code can be enabled.
145 #def _assert_units_complementarity(cdata):
146 #    """
147 #    Raise an exception if any units in either of the complementarity
148 #    expressions are inconsistent, and also check the standard block
149 #    methods.
150 #    """
151 #    if cdata._args[0] is not None:
152 #        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[0])
153 #    if cdata._args[1] is not None:
154 #        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[1])
155 #    _assert_units_consistent_block(cdata)
156 
157 def _assert_units_consistent_block(obj):
158     """
159     This method gets all the components from the block
160     and checks if the units are consistent on each of them
161     """
162     # check all the component objects
163     for component in obj.component_objects(descend_into=False, active=True):
164         assert_units_consistent(component)
165 
166 _component_data_handlers = {
167     Objective: _assert_units_consistent_property_expr,
168     Constraint:  _assert_units_consistent_constraint_data,
169     Var: _assert_units_consistent_expression,
170     DerivativeVar: _assert_units_consistent_expression,
171     Port: None,
172     Arc: _assert_units_consistent_arc_data,
173     Expression: _assert_units_consistent_property_expr,
174     Suffix: None,
175     Param: _assert_units_consistent_expression,
176     Set: None,
177     RangeSet: None,
178     Disjunct: _assert_units_consistent_block,
179     Disjunction: None,
180     BooleanVar: None,
181     Block: _assert_units_consistent_block,
182     ExternalFunction: None,
183     ContinuousSet: None, # ToDo: change this when continuous sets have units assigned
184     # complementarities that are not in normal form are not working yet
185     # see comment in test_check_units
186     # Complementarity: _assert_units_complementarity
187     }
188 
189 def assert_units_consistent(obj):
190     """
191     This method raises an exception if the units are not
192     consistent on the passed in object.  Argument obj can be one
193     of the following components: Pyomo Block (or Model),
194     Constraint, Objective, Expression, or it can be a Pyomo
195     expression object
196 
197     Parameters
198     ----------
199     obj : Pyomo component (e.g., Block, Model, Constraint, Objective, or Expression) or Pyomo expression
200        The object or expression to test
201 
202     Raises
203     ------
204     :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`
205     """
206     objtype = type(obj)
207     if objtype in native_types:
208         return
209     elif obj.is_expression_type() or objtype is IndexTemplate:
210         try:
211             _assert_units_consistent_expression(obj)
212         except UnitsError:
213             print('Units problem with expression {}'.format(obj))
214             raise
215         return
216 
217     # if object is not in our component handler, raise an exception
218     if obj.ctype not in _component_data_handlers:
219         raise TypeError("Units checking not supported for object of type {}.".format(obj.ctype))
220 
221     # get the function form the list of handlers
222     handler = _component_data_handlers[obj.ctype]
223     if handler is None:
224         return
225 
226     if obj.is_indexed():
227         # check all the component data objects
228         for cdata in obj.values():
229             try:
230                 handler(cdata)
231             except UnitsError:
232                 print('Error in units when checking {}'.format(cdata))
233                 raise
234     else:
235         try:
236             handler(obj)
237         except UnitsError:
238                 print('Error in units when checking {}'.format(obj))
239                 raise
240             
241
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyomo/util/check_units.py b/pyomo/util/check_units.py
--- a/pyomo/util/check_units.py
+++ b/pyomo/util/check_units.py
@@ -15,9 +15,9 @@
 """
 from pyomo.core.base.units_container import units, UnitsError
 from pyomo.core.base import (Objective, Constraint, Var, Param,
-                             Suffix, Set, RangeSet, Block,
+                             Suffix, Set, SetOf, RangeSet, Block,
                              ExternalFunction, Expression,
-                             value, BooleanVar)
+                             value, BooleanVar, BuildAction, BuildCheck)
 from pyomo.dae import ContinuousSet, DerivativeVar
 from pyomo.network import Port, Arc
 from pyomo.mpec import Complementarity
@@ -173,17 +173,24 @@
     Expression: _assert_units_consistent_property_expr,
     Suffix: None,
     Param: _assert_units_consistent_expression,
-    Set: None,
-    RangeSet: None,
     Disjunct: _assert_units_consistent_block,
     Disjunction: None,
     BooleanVar: None,
     Block: _assert_units_consistent_block,
     ExternalFunction: None,
-    ContinuousSet: None, # ToDo: change this when continuous sets have units assigned
+    # TODO: change this when Sets / ContinuousSets sets have units:
+    ContinuousSet: None,
+    Set: None,
+    SetOf: None,
+    RangeSet: None,
+    # TODO: Piecewise: _assert_units_consistent_piecewise,
+    # TODO: SOSConstraint: _assert_units_consistent_sos,
+    # TODO: LogicalConstriant: _assert_units_consistent_logical,
+    BuildAction: None,
+    BuildCheck: None,
     # complementarities that are not in normal form are not working yet
     # see comment in test_check_units
-    # Complementarity: _assert_units_complementarity
+    # TODO: Complementarity: _assert_units_complementarity
     }
 
 def assert_units_consistent(obj):

{"golden_diff": "diff --git a/pyomo/util/check_units.py b/pyomo/util/check_units.py\n--- a/pyomo/util/check_units.py\n+++ b/pyomo/util/check_units.py\n@@ -15,9 +15,9 @@\n \"\"\"\n from pyomo.core.base.units_container import units, UnitsError\n from pyomo.core.base import (Objective, Constraint, Var, Param,\n-                             Suffix, Set, RangeSet, Block,\n+                             Suffix, Set, SetOf, RangeSet, Block,\n                              ExternalFunction, Expression,\n-                             value, BooleanVar)\n+                             value, BooleanVar, BuildAction, BuildCheck)\n from pyomo.dae import ContinuousSet, DerivativeVar\n from pyomo.network import Port, Arc\n from pyomo.mpec import Complementarity\n@@ -173,17 +173,24 @@\n     Expression: _assert_units_consistent_property_expr,\n     Suffix: None,\n     Param: _assert_units_consistent_expression,\n-    Set: None,\n-    RangeSet: None,\n     Disjunct: _assert_units_consistent_block,\n     Disjunction: None,\n     BooleanVar: None,\n     Block: _assert_units_consistent_block,\n     ExternalFunction: None,\n-    ContinuousSet: None, # ToDo: change this when continuous sets have units assigned\n+    # TODO: change this when Sets / ContinuousSets sets have units:\n+    ContinuousSet: None,\n+    Set: None,\n+    SetOf: None,\n+    RangeSet: None,\n+    # TODO: Piecewise: _assert_units_consistent_piecewise,\n+    # TODO: SOSConstraint: _assert_units_consistent_sos,\n+    # TODO: LogicalConstriant: _assert_units_consistent_logical,\n+    BuildAction: None,\n+    BuildCheck: None,\n     # complementarities that are not in normal form are not working yet\n     # see comment in test_check_units\n-    # Complementarity: _assert_units_complementarity\n+    # TODO: Complementarity: _assert_units_complementarity\n     }\n \n def assert_units_consistent(obj):\n", "issue": "assert_units_consistent fails when model has reference to unindexed Var\n## Summary\r\n\r\nRunning `assert_units_consistent` on a model with a `Reference` to an unindexed variable results in an error.\r\n\r\n### Steps to reproduce the issue\r\n\r\n```console\r\nimport pyomo.environ as pyo\r\nfrom pyomo.util.check_units import assert_units_consistent\r\n\r\nm = pyo.ConcreteModel()\r\n\r\nm.x = pyo.Var(initialize=1, units=pyo.units.m)\r\nm.y = pyo.Var(initialize=1, units=pyo.units.m)\r\nm.z = pyo.Reference(m.x)\r\nm.expr = pyo.Expression(expr=(m.x+m.z[None]))\r\nassert_units_consistent(m)\r\n```\r\n\r\n### Error Message\r\n\r\n>   Traceback (most recent call last):\r\n> \r\n>   File ~\\Work\\assert_units_consistent_fail.py:10 in <module>\r\n>     assert_units_consistent(m)\r\n> \r\n>   File ~\\miniconda3\\envs\\idaes-new\\lib\\site-packages\\pyomo\\util\\check_units.py:236 in assert_units_consistent\r\n>     handler(obj)\r\n> \r\n>   File ~\\miniconda3\\envs\\idaes-new\\lib\\site-packages\\pyomo\\util\\check_units.py:164 in _assert_units_consistent_block\r\n>     assert_units_consistent(component)\r\n> \r\n>   File ~\\miniconda3\\envs\\idaes-new\\lib\\site-packages\\pyomo\\util\\check_units.py:219 in assert_units_consistent\r\n>     raise TypeError(\"Units checking not supported for object of type {}.\".format(obj.ctype))\r\n> \r\n> TypeError: Units checking not supported for object of type <class 'pyomo.core.base.set.SetOf'>.\r\n\r\n### Information on your system\r\n\r\nPyomo version: 6.4.0\r\nPython version: 3.9\r\nOperating system: Windows 11\r\nHow Pyomo was installed: Through IDAES install (I think the script uses pip?)\r\n\n", "before_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and\n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain\n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  __________________________________________________________________________\n#\n#\n\"\"\" Pyomo Units Checking Module\nThis module has some helpful methods to support checking units on Pyomo\nmodule objects.\n\"\"\"\nfrom pyomo.core.base.units_container import units, UnitsError\nfrom pyomo.core.base import (Objective, Constraint, Var, Param,\n                             Suffix, Set, RangeSet, Block,\n                             ExternalFunction, Expression,\n                             value, BooleanVar)\nfrom pyomo.dae import ContinuousSet, DerivativeVar\nfrom pyomo.network import Port, Arc\nfrom pyomo.mpec import Complementarity\nfrom pyomo.gdp import Disjunct, Disjunction\nfrom pyomo.core.expr.template_expr import IndexTemplate\nfrom pyomo.core.expr.numvalue import native_types\nfrom pyomo.util.components import iter_component\n\ndef check_units_equivalent(*args):\n    \"\"\"\n    Returns True if the units associated with each of the\n    expressions passed as arguments are all equivalent (and False\n    otherwise).\n\n    Note that this method will raise an exception if the units are\n    inconsistent within an expression (since the units for that\n    expression are not valid).\n\n    Parameters\n    ----------\n    args : an argument list of Pyomo expressions\n\n    Returns\n    -------\n    bool : True if all the expressions passed as argments have the same units\n    \"\"\"\n    try:\n        assert_units_equivalent(*args)\n        return True\n    except UnitsError:\n        return False\n\ndef assert_units_equivalent(*args):\n    \"\"\"\n    Raise an exception if the units are inconsistent within an\n    expression, or not equivalent across all the passed\n    expressions.\n\n    Parameters\n    ----------\n    args : an argument list of Pyomo expressions\n        The Pyomo expressions to test\n\n    Raises\n    ------\n    :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`\n    \"\"\"\n    # this call will raise an exception if an inconsistency is found\n    pint_units = [units._get_pint_units(arg) for arg in args]\n    pint_unit_compare = pint_units[0]\n    for pint_unit in pint_units:\n        if not units._equivalent_pint_units(pint_unit_compare, pint_unit):\n            raise UnitsError(\n                \"Units between {} and {} are not consistent.\".format(\n                    str(pint_unit_compare), str(pint_unit)))\n\ndef _assert_units_consistent_constraint_data(condata):\n    \"\"\"\n    Raise an exception if the any units in lower, body, upper on a\n    ConstraintData object are not consistent or are not equivalent\n    with each other.\n    \"\"\"\n    # Pyomo can rearrange expressions, resulting in a value\n    # of 0 for upper or lower that does not have units associated\n    # Therefore, if the lower and/or upper is 0, we allow it to be unitless\n    # and check the consistency of the body only\n    args = list()\n    if condata.lower is not None and value(condata.lower) != 0.0:\n        args.append(condata.lower)\n\n    args.append(condata.body)\n\n    if condata.upper is not None and value(condata.upper) != 0.0:\n        args.append(condata.upper)\n\n    if len(args) == 1:\n        assert_units_consistent(*args)\n    else:\n        assert_units_equivalent(*args)\n\ndef _assert_units_consistent_arc_data(arcdata):\n    \"\"\"\n    Raise an exception if the any units do not match for the connected ports\n    \"\"\"\n    sport = arcdata.source\n    dport = arcdata.destination\n    if sport is None or dport is None:\n        # nothing to check\n        return\n\n    # both sport and dport are not None\n    # iterate over the vars in one and check against the other\n    for key in sport.vars:\n        svar = sport.vars[key]\n        dvar = dport.vars[key]\n\n        if svar.is_indexed():\n            for k in svar:\n                svardata = svar[k]\n                dvardata = dvar[k]\n                assert_units_equivalent(svardata, dvardata)\n        else:\n            assert_units_equivalent(svar, dvar)\n\ndef _assert_units_consistent_property_expr(obj):\n    \"\"\"\n    Check the .expr property of the object and raise\n    an exception if the units are not consistent\n    \"\"\"\n    _assert_units_consistent_expression(obj.expr)\n\ndef _assert_units_consistent_expression(expr):\n    \"\"\"\n    Raise an exception if any units in expr are inconsistent.\n    \"\"\"\n    # this will raise an exception if the units are not consistent\n    # in the expression\n    pint_unit = units._get_pint_units(expr)\n    # pyomo_unit = units.get_units(expr)\n\n# Complementarities that are not in standard form do not\n# current work with the checking code. The Units container\n# should be modified to allow sum and relationals with zero\n# terms (e.g., unitless). Then this code can be enabled.\n#def _assert_units_complementarity(cdata):\n#    \"\"\"\n#    Raise an exception if any units in either of the complementarity\n#    expressions are inconsistent, and also check the standard block\n#    methods.\n#    \"\"\"\n#    if cdata._args[0] is not None:\n#        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[0])\n#    if cdata._args[1] is not None:\n#        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[1])\n#    _assert_units_consistent_block(cdata)\n\ndef _assert_units_consistent_block(obj):\n    \"\"\"\n    This method gets all the components from the block\n    and checks if the units are consistent on each of them\n    \"\"\"\n    # check all the component objects\n    for component in obj.component_objects(descend_into=False, active=True):\n        assert_units_consistent(component)\n\n_component_data_handlers = {\n    Objective: _assert_units_consistent_property_expr,\n    Constraint:  _assert_units_consistent_constraint_data,\n    Var: _assert_units_consistent_expression,\n    DerivativeVar: _assert_units_consistent_expression,\n    Port: None,\n    Arc: _assert_units_consistent_arc_data,\n    Expression: _assert_units_consistent_property_expr,\n    Suffix: None,\n    Param: _assert_units_consistent_expression,\n    Set: None,\n    RangeSet: None,\n    Disjunct: _assert_units_consistent_block,\n    Disjunction: None,\n    BooleanVar: None,\n    Block: _assert_units_consistent_block,\n    ExternalFunction: None,\n    ContinuousSet: None, # ToDo: change this when continuous sets have units assigned\n    # complementarities that are not in normal form are not working yet\n    # see comment in test_check_units\n    # Complementarity: _assert_units_complementarity\n    }\n\ndef assert_units_consistent(obj):\n    \"\"\"\n    This method raises an exception if the units are not\n    consistent on the passed in object.  Argument obj can be one\n    of the following components: Pyomo Block (or Model),\n    Constraint, Objective, Expression, or it can be a Pyomo\n    expression object\n\n    Parameters\n    ----------\n    obj : Pyomo component (e.g., Block, Model, Constraint, Objective, or Expression) or Pyomo expression\n       The object or expression to test\n\n    Raises\n    ------\n    :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`\n    \"\"\"\n    objtype = type(obj)\n    if objtype in native_types:\n        return\n    elif obj.is_expression_type() or objtype is IndexTemplate:\n        try:\n            _assert_units_consistent_expression(obj)\n        except UnitsError:\n            print('Units problem with expression {}'.format(obj))\n            raise\n        return\n\n    # if object is not in our component handler, raise an exception\n    if obj.ctype not in _component_data_handlers:\n        raise TypeError(\"Units checking not supported for object of type {}.\".format(obj.ctype))\n\n    # get the function form the list of handlers\n    handler = _component_data_handlers[obj.ctype]\n    if handler is None:\n        return\n\n    if obj.is_indexed():\n        # check all the component data objects\n        for cdata in obj.values():\n            try:\n                handler(cdata)\n            except UnitsError:\n                print('Error in units when checking {}'.format(cdata))\n                raise\n    else:\n        try:\n            handler(obj)\n        except UnitsError:\n                print('Error in units when checking {}'.format(obj))\n                raise\n            \n", "path": "pyomo/util/check_units.py"}], "after_files": [{"content": "#  ___________________________________________________________________________\n#\n#  Pyomo: Python Optimization Modeling Objects\n#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC\n#  Under the terms of Contract DE-NA0003525 with National Technology and\n#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain\n#  rights in this software.\n#  This software is distributed under the 3-clause BSD License.\n#  __________________________________________________________________________\n#\n#\n\"\"\" Pyomo Units Checking Module\nThis module has some helpful methods to support checking units on Pyomo\nmodule objects.\n\"\"\"\nfrom pyomo.core.base.units_container import units, UnitsError\nfrom pyomo.core.base import (Objective, Constraint, Var, Param,\n                             Suffix, Set, SetOf, RangeSet, Block,\n                             ExternalFunction, Expression,\n                             value, BooleanVar, BuildAction, BuildCheck)\nfrom pyomo.dae import ContinuousSet, DerivativeVar\nfrom pyomo.network import Port, Arc\nfrom pyomo.mpec import Complementarity\nfrom pyomo.gdp import Disjunct, Disjunction\nfrom pyomo.core.expr.template_expr import IndexTemplate\nfrom pyomo.core.expr.numvalue import native_types\nfrom pyomo.util.components import iter_component\n\ndef check_units_equivalent(*args):\n    \"\"\"\n    Returns True if the units associated with each of the\n    expressions passed as arguments are all equivalent (and False\n    otherwise).\n\n    Note that this method will raise an exception if the units are\n    inconsistent within an expression (since the units for that\n    expression are not valid).\n\n    Parameters\n    ----------\n    args : an argument list of Pyomo expressions\n\n    Returns\n    -------\n    bool : True if all the expressions passed as argments have the same units\n    \"\"\"\n    try:\n        assert_units_equivalent(*args)\n        return True\n    except UnitsError:\n        return False\n\ndef assert_units_equivalent(*args):\n    \"\"\"\n    Raise an exception if the units are inconsistent within an\n    expression, or not equivalent across all the passed\n    expressions.\n\n    Parameters\n    ----------\n    args : an argument list of Pyomo expressions\n        The Pyomo expressions to test\n\n    Raises\n    ------\n    :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`\n    \"\"\"\n    # this call will raise an exception if an inconsistency is found\n    pint_units = [units._get_pint_units(arg) for arg in args]\n    pint_unit_compare = pint_units[0]\n    for pint_unit in pint_units:\n        if not units._equivalent_pint_units(pint_unit_compare, pint_unit):\n            raise UnitsError(\n                \"Units between {} and {} are not consistent.\".format(\n                    str(pint_unit_compare), str(pint_unit)))\n\ndef _assert_units_consistent_constraint_data(condata):\n    \"\"\"\n    Raise an exception if the any units in lower, body, upper on a\n    ConstraintData object are not consistent or are not equivalent\n    with each other.\n    \"\"\"\n    # Pyomo can rearrange expressions, resulting in a value\n    # of 0 for upper or lower that does not have units associated\n    # Therefore, if the lower and/or upper is 0, we allow it to be unitless\n    # and check the consistency of the body only\n    args = list()\n    if condata.lower is not None and value(condata.lower) != 0.0:\n        args.append(condata.lower)\n\n    args.append(condata.body)\n\n    if condata.upper is not None and value(condata.upper) != 0.0:\n        args.append(condata.upper)\n\n    if len(args) == 1:\n        assert_units_consistent(*args)\n    else:\n        assert_units_equivalent(*args)\n\ndef _assert_units_consistent_arc_data(arcdata):\n    \"\"\"\n    Raise an exception if the any units do not match for the connected ports\n    \"\"\"\n    sport = arcdata.source\n    dport = arcdata.destination\n    if sport is None or dport is None:\n        # nothing to check\n        return\n\n    # both sport and dport are not None\n    # iterate over the vars in one and check against the other\n    for key in sport.vars:\n        svar = sport.vars[key]\n        dvar = dport.vars[key]\n\n        if svar.is_indexed():\n            for k in svar:\n                svardata = svar[k]\n                dvardata = dvar[k]\n                assert_units_equivalent(svardata, dvardata)\n        else:\n            assert_units_equivalent(svar, dvar)\n\ndef _assert_units_consistent_property_expr(obj):\n    \"\"\"\n    Check the .expr property of the object and raise\n    an exception if the units are not consistent\n    \"\"\"\n    _assert_units_consistent_expression(obj.expr)\n\ndef _assert_units_consistent_expression(expr):\n    \"\"\"\n    Raise an exception if any units in expr are inconsistent.\n    \"\"\"\n    # this will raise an exception if the units are not consistent\n    # in the expression\n    pint_unit = units._get_pint_units(expr)\n    # pyomo_unit = units.get_units(expr)\n\n# Complementarities that are not in standard form do not\n# current work with the checking code. The Units container\n# should be modified to allow sum and relationals with zero\n# terms (e.g., unitless). Then this code can be enabled.\n#def _assert_units_complementarity(cdata):\n#    \"\"\"\n#    Raise an exception if any units in either of the complementarity\n#    expressions are inconsistent, and also check the standard block\n#    methods.\n#    \"\"\"\n#    if cdata._args[0] is not None:\n#        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[0])\n#    if cdata._args[1] is not None:\n#        pyomo_unit, pint_unit = units._get_units_tuple(cdata._args[1])\n#    _assert_units_consistent_block(cdata)\n\ndef _assert_units_consistent_block(obj):\n    \"\"\"\n    This method gets all the components from the block\n    and checks if the units are consistent on each of them\n    \"\"\"\n    # check all the component objects\n    for component in obj.component_objects(descend_into=False, active=True):\n        assert_units_consistent(component)\n\n_component_data_handlers = {\n    Objective: _assert_units_consistent_property_expr,\n    Constraint:  _assert_units_consistent_constraint_data,\n    Var: _assert_units_consistent_expression,\n    DerivativeVar: _assert_units_consistent_expression,\n    Port: None,\n    Arc: _assert_units_consistent_arc_data,\n    Expression: _assert_units_consistent_property_expr,\n    Suffix: None,\n    Param: _assert_units_consistent_expression,\n    Disjunct: _assert_units_consistent_block,\n    Disjunction: None,\n    BooleanVar: None,\n    Block: _assert_units_consistent_block,\n    ExternalFunction: None,\n    # TODO: change this when Sets / ContinuousSets sets have units:\n    ContinuousSet: None,\n    Set: None,\n    SetOf: None,\n    RangeSet: None,\n    # TODO: Piecewise: _assert_units_consistent_piecewise,\n    # TODO: SOSConstraint: _assert_units_consistent_sos,\n    # TODO: LogicalConstriant: _assert_units_consistent_logical,\n    BuildAction: None,\n    BuildCheck: None,\n    # complementarities that are not in normal form are not working yet\n    # see comment in test_check_units\n    # TODO: Complementarity: _assert_units_complementarity\n    }\n\ndef assert_units_consistent(obj):\n    \"\"\"\n    This method raises an exception if the units are not\n    consistent on the passed in object.  Argument obj can be one\n    of the following components: Pyomo Block (or Model),\n    Constraint, Objective, Expression, or it can be a Pyomo\n    expression object\n\n    Parameters\n    ----------\n    obj : Pyomo component (e.g., Block, Model, Constraint, Objective, or Expression) or Pyomo expression\n       The object or expression to test\n\n    Raises\n    ------\n    :py:class:`pyomo.core.base.units_container.UnitsError`, :py:class:`pyomo.core.base.units_container.InconsistentUnitsError`\n    \"\"\"\n    objtype = type(obj)\n    if objtype in native_types:\n        return\n    elif obj.is_expression_type() or objtype is IndexTemplate:\n        try:\n            _assert_units_consistent_expression(obj)\n        except UnitsError:\n            print('Units problem with expression {}'.format(obj))\n            raise\n        return\n\n    # if object is not in our component handler, raise an exception\n    if obj.ctype not in _component_data_handlers:\n        raise TypeError(\"Units checking not supported for object of type {}.\".format(obj.ctype))\n\n    # get the function form the list of handlers\n    handler = _component_data_handlers[obj.ctype]\n    if handler is None:\n        return\n\n    if obj.is_indexed():\n        # check all the component data objects\n        for cdata in obj.values():\n            try:\n                handler(cdata)\n            except UnitsError:\n                print('Error in units when checking {}'.format(cdata))\n                raise\n    else:\n        try:\n            handler(obj)\n        except UnitsError:\n                print('Error in units when checking {}'.format(obj))\n                raise\n            \n", "path": "pyomo/util/check_units.py"}]}