WikiWatershed/gwlf-e

Upgrade to Python 3

Closed this issue · 1 comments

Most of the upgrade is going well. There are some numeric discrepancies though:

pipenv run nosetests --verbosity=0 --nologcapture test.integrationtests.test_output_gms8
======================================================================
FAIL: test_loads (test.integrationtests.test_output_gms8.gms8_TestOutput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/ttuhinanshu/dev/mmw-gwlfe/test/integrationtests/test_output.py", line 125, in test_loads
    raise AssertionError("Not all values within margin of error")
AssertionError: Not all values within margin of error
-------------------- >> begin captured stdout << ---------------------
AssertionError on Sediment (Low-Density Mixed)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 11.40488149
Max relative difference: 0.00172414
 x: array(6626.236146)
 y: array(6614.831265)
AssertionError on TotalN (Low-Density Mixed)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 0.30493111
Max relative difference: 0.00172414
 x: array(177.164974)
 y: array(176.860043)
AssertionError on TotalP (Low-Density Mixed)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 0.03454588
Max relative difference: 0.00172414
 x: array(20.071153)
 y: array(20.036608)

--------------------- >> end captured stdout << ----------------------
======================================================================
FAIL: test_summary_loads (test.integrationtests.test_output_gms8.gms8_TestOutput)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/ttuhinanshu/dev/mmw-gwlfe/test/integrationtests/test_output.py", line 104, in test_summary_loads
    raise AssertionError("Not all values within margin of error")
AssertionError: Not all values within margin of error
-------------------- >> begin captured stdout << ---------------------
AssertionError on Sediment (Total Loads)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 11.40488149
Max relative difference: 3.34669102e-06
 x: array(3407819.716665)
 y: array(3407808.311784)
AssertionError on TotalN (Total Loads)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 0.30493111
Max relative difference: 2.29903047e-06
 x: array(132634.957626)
 y: array(132634.652695)
AssertionError on TotalP (Total Loads)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 0.03454588
Max relative difference: 3.47984992e-06
 x: array(9927.438259)
 y: array(9927.403713)
AssertionError on Sediment (Loading Rates)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 5.77569972e-05
Max relative difference: 3.34669102e-06
 x: array(17.257999)
 y: array(17.257941)
AssertionError on TotalN (Loading Rates)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 1.54424271e-06
Max relative difference: 2.29903047e-06
 x: array(0.671695)
 y: array(0.671693)
AssertionError on TotalP (Loading Rates)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 1.74948421e-07
Max relative difference: 3.47984992e-06
 x: array(0.050275)
 y: array(0.050275)
AssertionError on Sediment (Mean Annual Concentration)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 1.77370757e-05
Max relative difference: 3.34669102e-06
 x: array(5.299902)
 y: array(5.299884)
AssertionError on TotalN (Mean Annual Concentration)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 4.74234314e-07
Max relative difference: 2.29903047e-06
 x: array(0.206276)
 y: array(0.206276)
AssertionError on TotalP (Mean Annual Concentration)

Not equal to tolerance rtol=1e-07, atol=0

Mismatched elements: 1 / 1 (100%)
Max absolute difference: 5.37263628e-08
Max relative difference: 3.47984992e-06
 x: array(0.015439)
 y: array(0.015439)

--------------------- >> end captured stdout << ----------------------

There are 4 failing test cases:

❯ pipenv run nosetests --verbosity=3 2>&1 | grep FAIL
test_loads (test.integrationtests.test_output_gms8.gms8_TestOutput) ... FAIL
test_summary_loads (test.integrationtests.test_output_gms8.gms8_TestOutput) ... FAIL
test_loads (test.integrationtests.test_output_nurbbank_zero.nurbbank_zero_TestOutput) ... FAIL
test_summary_loads (test.integrationtests.test_output_nurbbank_zero.nurbbank_zero_TestOutput) ... FAIL
test_loads (test.integrationtests.test_output_test1.test1_TestOutput) ... FAIL
test_summary_loads (test.integrationtests.test_output_test1.test1_TestOutput) ... FAIL
test_loads (test.integrationtests.test_output_test10.test10_TestOutput) ... FAIL
test_summary_loads (test.integrationtests.test_output_test10.test10_TestOutput) ... FAIL

All the differences are only in the Low-Density Mixed land cover type. The relative difference for test_loads averages 0.0014275025. The relative difference for test_summary_loads averages 4.61E-06.

Looking in to why only this land use type was causing issues, I added some debug statements to see how the values are being read from the GMS file:

diff --git a/gwlfe/Parser.py b/gwlfe/Parser.py
index d2050eb..82c5067 100644
--- a/gwlfe/Parser.py
+++ b/gwlfe/Parser.py
@@ -626,7 +626,7 @@ class GmsReader(object):
         z.n23b = self.next(float)  # High Density Urban Area (Ha)
         z.n23c = self.next(float)  # High Density Urban (Constructed Wetlands): % Drainage Used
         z.n24 = self.next(float)  # Hay/Pasture Area (Ha)
-        z.n24b = self.next(float)  # Low Density Urban Area (ha Ha
+        z.n24b = self.next(float, print=True)  # Low Density Urban Area (ha Ha
         z.n24c = self.next(float)  # Low Density Urban (Constructed Wetlands): % Drainage Used
         z.n24d = self.next(float)  # High Density Urban (Bioretention Areas): % Drainage Used
         z.n24e = self.next(float)  # Low Density Urban (Bioretention Areas): % Drainage Used
@@ -1247,7 +1247,7 @@ class GmsReader(object):
 
         return z
 
-    def next(self, typ):
+    def next(self, typ, print=False):
         """
         Pop the next token and cast it using the given callable function
         or type. If a scalar value is passed instead, assert that the
@@ -1255,8 +1255,14 @@ class GmsReader(object):
         """
         value, line_no, col_no = self.fp.next()
 
+        if print:
+            log.warn('==> type(value) {}'.format(type(value)))
+            log.warn('==> value {}'.format(value))
+
         if callable(typ):
             try:
+                if print:
+                    log.warn('==> typ(value) {}'.format(typ(value)))
                 return typ(value)
             except ValueError:
                 log.error('Unexpected token at Line {} Column {}'.format(line_no, col_no))

and in Python 2 the value gets truncated:

❯ pipenv run nosetests --verbosity=3 --nologcapture test.integrationtests.test_output_gms8

WARNING:gwlfe.Parser:==> type(value) <type 'str'>
WARNING:gwlfe.Parser:==> value 19.08022010634788
WARNING:gwlfe.Parser:==> typ(value) 19.0802201063

whereas in Python 3 the full value is used:

❯ pipenv run nosetests --verbosity=0 --nologcapture test.integrationtests.test_output_gms8
==> type(value) <class 'str'>
==> value 19.08022010634788
==> typ(value) 19.08022010634788

Which leads me to believe that while the numbers are different, they are more accurate in Python 3, so we should update the tests to match the new values, rather than try to fix the code to match the old tests.