Repository: lbl-srg/BuildingsPy

Issue:
check for wrong derivative implementation
Dymola 2021x beta2 issues warnings such as
```
Warning: function Buildings.Utilities.Psychrometrics.Functions.saturationPressureLiquid specified derivative Buildings.Utilities.Psychrometrics.Functions.BaseClasses.der_saturationPressureLiquid, but
argument TSat function did not match argument Tsat of derivative.
```
This issue is to catch these warnings and fail the unit tests.

Comments:

Patch:
diff --git a/buildingspy/CHANGES.txt b/buildingspy/CHANGES.txt
index ebf666b..32cc572 100644
--- a/buildingspy/CHANGES.txt
+++ b/buildingspy/CHANGES.txt
@@ -3,7 +3,7 @@ BuildingsPy Changelog
 
 Version 2.2.0, xxx, 2020 -- Release 2.2
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- xxx
+- Added check for wrong derivative implementation that is reported by Dymola 2021x (https://github.com/lbl-srg/BuildingsPy/issues/376).
 
 Version 2.1.0, May 28, 2020 -- Release 2.1
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/buildingspy/development/error_dictionary_dymola.py b/buildingspy/development/error_dictionary_dymola.py
index 1fea2f4..3579230 100644
--- a/buildingspy/development/error_dictionary_dymola.py
+++ b/buildingspy/development/error_dictionary_dymola.py
@@ -24,68 +24,58 @@ class ErrorDictionary(ed.ErrorDictionary):
         """
         self._error_dict = dict()
         # Set the error dictionaries.
-        # Note that buildingspy_var needs to be a unique variable name.
         self._error_dict["numerical Jacobians"] = {
             'tool_message': r"Number of numerical Jacobians: (\d*)",
             'is_regex': True,
             'counter': 0,
-            'buildingspy_var': "lJac",
             'model_message': "Numerical Jacobian in '{}'.",
             'summary_message': "Number of models with numerical Jacobian                     : {}\n"}
 
         self._error_dict["unused connector"] = {
             'tool_message': "Warning: The following connector variables are not used in the model",
             'counter': 0,
-            'buildingspy_var': "iUnuCon",
             'model_message': "Unused connector variables in '{}'.\n",
             'summary_message': "Number of models with unused connector variables             : {}\n"}
 
         self._error_dict["parameter with start value only"] = {
             'tool_message': "Warning: The following parameters don't have any value, only a start value",
             'counter': 0,
-            'buildingspy_var': "iParNoSta",
             'model_message': "Parameter with start value only in '{}'.\n",
             'summary_message': "Number of models with parameters that only have a start value: {}\n"}
 
         self._error_dict["redundant consistent initial conditions"] = {
             'tool_message': "Redundant consistent initial conditions:",
             'counter': 0,
-            'buildingspy_var': "iRedConIni",
             'model_message': "Redundant consistent initial conditions in '{}'.\n",
             'summary_message': "Number of models with redundant consistent initial conditions: {}\n"}
 
         self._error_dict["redundant connection"] = {
             'tool_message': "Redundant connection",
             'counter': 0,
-            'buildingspy_var': "iRedConSta",
             'model_message': "Redundant connections in '{}'.\n",
             'summary_message': "Number of models with redundant connections                  : {}\n"}
 
         self._error_dict["type inconsistent definition equations"] = {
             'tool_message': "Type inconsistent definition equation",
             'counter': 0,
-            'buildingspy_var': "iTypIncDef",
             'model_message': "Type inconsistent definition equations in '{}'.\n",
             'summary_message': "Number of models with type inconsistent definition equations : {}\n"}
 
         self._error_dict["type incompatibility"] = {
             'tool_message': "but they must be compatible",
             'counter': 0,
-            'buildingspy_var': "iTypInc",
             'model_message': "Type incompatibility in '{}'.\n",
             'summary_message': "Number of models with incompatible types                     : {}\n"}
 
         self._error_dict["unspecified initial conditions"] = {
             'tool_message': "Dymola has selected default initial condition",
             'counter': 0,
-            'buildingspy_var': "iUnsIni",
             'model_message': "Unspecified initial conditions in '{}'.\n",
             'summary_message': "Number of models with unspecified initial conditions         : {}\n"}
 
         self._error_dict["invalid connect"] = {
             'tool_message': "The model contained invalid connect statements.",
             'counter': 0,
-            'buildingspy_var': "iInvCon",
             'model_message': "Invalid connect statements in '{}'.\n",
             'summary_message': "Number of models with invalid connect statements             : {}\n"}
 
@@ -95,21 +85,18 @@ class ErrorDictionary(ed.ErrorDictionary):
         self._error_dict["differentiated if"] = {
             'tool_message': "Differentiating (if",
             'counter': 0,
-            'buildingspy_var': "iDiffIf",
             'model_message': "Differentiated if-expression under assumption it is smooth in '{}'.\n",
             'summary_message': "Number of models with differentiated if-expression           : {}\n"}
 
         self._error_dict["redeclare non-replaceable"] = \
             {'tool_message': "Warning: Redeclaration of non-replaceable requires type equivalence",
              'counter': 0,
-             'buildingspy_var': "iRedNon",
              'model_message': "Redeclaration of non-replaceable class in '{}'.\n",
              'summary_message': "Number of models with redeclaration of non-replaceable class : {}\n"}
 
         self._error_dict["experiment annotation"] = {
             'tool_message': "Warning: Failed to interpret experiment annotation",
             'counter': 0,
-            'buildingspy_var': "iExpAnn",
             'model_message': "Failed to interpret experiment annotation in '{}'.\n",
             'summary_message': "Number of models with wrong experiment annotation            : {}\n"}
 
@@ -119,27 +106,33 @@ class ErrorDictionary(ed.ErrorDictionary):
         self._error_dict["file not found"] = {
             'tool_message': "which was not found",
             'counter': 0,
-            'buildingspy_var': "iFilNotFou",
             'model_message': "File not found in '{}'.\n",
             'summary_message': "Number of models with file not found                         : {}\n"}
 
         self._error_dict["stateGraphRoot missing"] = {
             'tool_message': "A \\\"stateGraphRoot\\\" component was automatically introduced.",
             'counter': 0,
-            'buildingspy_var': "iStaGraRooMis",
             'model_message': "\"inner Modelica.StateGraph.StateGraphRoot\" is missing in '{}'.\n",
             'summary_message': "Number of models with missing StateGraphRoot                 : {}\n"}
 
         self._error_dict["mismatched displayUnits"] = {
             'tool_message': "Mismatched displayUnit",
             'counter': 0,
-            'buildingspy_var': "iMisDisUni",
             'model_message': "Mismatched displayUnit in '{}'.\n",
             'summary_message': "Number of models with mismatched displayUnit                 : {}\n"}
 
         self._error_dict["suspicious attributes"] = {
             'tool_message': "which is suspicious",
             'counter': 0,
-            'buildingspy_var': "iSus",
             'model_message': "Check min and max attributes in '{}'.\n",
             'summary_message': "Number of models with suspicious attributes (likely min/max) : {}\n"}
+
+        # This captures
+        # Warning: function Buildings.Utilities.Psychrometrics.Functions.saturationPressureLiquid
+        # specified derivative Buildings.Utilities.Psychrometrics.Functions.BaseClasses.der_saturationPressureLiquid,
+        # but argument TSat function did not match argument Tsat of derivative
+        self._error_dict["wrong derivative specification"] = {
+            'tool_message': "did not match argument",
+            'counter': 0,
+            'model_message': "Check specification of derivative of '{}'.\n",
+            'summary_message': "Number of models with wrong derivative specification         : {}\n"}


Test patch:
diff --git a/buildingspy/tests/test_development_error_dictionary.py b/buildingspy/tests/test_development_error_dictionary.py
index 73b7aa1..d2ae84f 100644
--- a/buildingspy/tests/test_development_error_dictionary.py
+++ b/buildingspy/tests/test_development_error_dictionary.py
@@ -41,7 +41,8 @@ class Test_development_error_dictionary(unittest.TestCase):
                              'unused connector',
                              'stateGraphRoot missing',
                              'mismatched displayUnits',
-                             'suspicious attributes'])
+                             'suspicious attributes',
+                             'wrong derivative specification'])
 
         self.assertEqual(len(k), len(k_expected), "Wrong number of keys.")
         for i in range(len(k)):
@@ -67,7 +68,8 @@ class Test_development_error_dictionary(unittest.TestCase):
                              'Warning: The following connector variables are not used in the model',
                              "A \\\"stateGraphRoot\\\" component was automatically introduced.",
                              "Mismatched displayUnit",
-                             "which is suspicious"])
+                             "which is suspicious",
+                             "did not match argument"])
 
         self.assertEqual(len(k), len(k_expected), "Wrong number of tool messages.")
         for i in range(len(k)):