Repository: ioos/compliance-checker

Issue:
CF dimension order check incorrect for some dimensions
I have a file with the following structure:
```
dimensions:
	TIME = 8064 ;
	name_strlen = 40 ;
	INSTRUMENT = 1 ;
variables:
        char station_name(name_strlen) ;
		station_name:cf_role = "timeseries_id" ;
	double LATITUDE ;
	double LONGITUDE ;
	double TIME(TIME) ;
		TIME:axis = "T" ;
	float DEPTH_TEMP(INSTRUMENT) ;
		DEPTH_TEMP:axis = "Z" ;
	float TEMP(INSTRUMENT, TIME) ;
```
and I get
```

Name                             Priority:     Score:Reasoning
--------------------------------------------------------------------------------
§2.4 Dimension Order                   :2:     2/ 4 : TEMP's dimensions are not
                                                      in the recommended order
                                                      T, Z, Y, X. They are
                                                      INSTRUMENT, TIME,
```
Which is incorrect according to CF-1.6 [section 2.4](http://cfconventions.org/cf-conventions/v1.6.0/cf-conventions.html#dimensions).

This error is _not_ reported if I remove the `INSTRUMENT` dimension from `DEPTH_TEMP`, or add it to `station_name`. 

I suspect the checker is being fooled by the fact that `INSTRUMENT` is the only dimension for `DEPTH_TEMP`, and that variable has `axis = "Z"`. However, it is *not* a coordinate variable.



Discussion:

Resolving patch:
diff --git a/compliance_checker/cf/cf.py b/compliance_checker/cf/cf.py
--- a/compliance_checker/cf/cf.py
+++ b/compliance_checker/cf/cf.py
@@ -674,7 +674,7 @@ def _dims_in_order(self, dimension_order):
         :return: Returns True if the dimensions are in order U*, T, Z, Y, X,
                  False otherwise
         '''
-        regx = regex.compile(r'^L?I?U*T?Z?(?:(?:Y?X?)|(?:C?)|(?:A+))$')
+        regx = regex.compile(r'^[^TZYX]*T?Z?Y?X?$')
         dimension_string = ''.join(dimension_order)
         return regx.match(dimension_string) is not None
 


Test patch:
diff --git a/compliance_checker/tests/data/dimension_order.cdl b/compliance_checker/tests/data/dimension_order.cdl
new file mode 100644
--- /dev/null
+++ b/compliance_checker/tests/data/dimension_order.cdl
@@ -0,0 +1,41 @@
+netcdf dimension_order {
+dimensions:
+    TIME = 4 ;
+    INSTRUMENT = 2 ;
+variables:
+    double TIME(TIME) ;
+        TIME:axis = "T" ;
+        TIME:standard_name = "time" ;
+        TIME:units = "days since 1970-01-01T00:00:00 UTC" ;
+    float NOMINAL_DEPTH(INSTRUMENT);
+        NOMINAL_DEPTH:axis = "Z" ;
+        NOMINAL_DEPTH:positive = "down" ;
+        NOMINAL_DEPTH:standard_name = "depth" ;
+        NOMINAL_DEPTH:units = "m" ;
+    float LATITUDE ;
+        LATITUDE:axis = "Y" ;
+        LATITUDE:standard_name = "latitude" ;
+        LATITUDE:units = "degrees_north" ;
+    float LONGITUDE ;
+        LONGITUDE:axis = "X" ;
+        LONGITUDE:standard_name = "longitude" ;
+        LONGITUDE:units = "degrees_east" ;
+    float TEMP(INSTRUMENT, TIME) ;
+        TEMP:standard_name = "sea_water_temperature" ;
+        TEMP:units = "degrees_Celsius" ;
+        TEMP:coordinates = "TIME NOMINAL_DEPTH LATITUDE LONGITUDE" ;
+
+data:
+
+ TIME = 24608.65, 24608.66, 24608.67, 24608.68 ;
+
+ NOMINAL_DEPTH = 22, 107 ;
+
+ LATITUDE = -27.3415 ;
+
+ LONGITUDE = 153.5619 ;
+
+ TEMP = 21.20, 21.21, 21.21, 21.21,
+        12.01, 12.05, 12.08, 12.03 ;
+
+}
diff --git a/compliance_checker/tests/resources.py b/compliance_checker/tests/resources.py
--- a/compliance_checker/tests/resources.py
+++ b/compliance_checker/tests/resources.py
@@ -113,4 +113,5 @@ def generate_dataset(cdl_path, nc_path):
     'bad_cell_measure2'                    : get_filename('tests/data/bad_cell_measure2.cdl'),
     'bad_cf_role'                          : get_filename('tests/data/bad_cf_role.cdl'),
     'ioos_gold_1_1'                        : get_filename('tests/data/ioos_1_1.cdl'),
+    'dimension_order'                      : get_filename('tests/data/dimension_order.cdl')
 }
diff --git a/compliance_checker/tests/test_cf.py b/compliance_checker/tests/test_cf.py
--- a/compliance_checker/tests/test_cf.py
+++ b/compliance_checker/tests/test_cf.py
@@ -173,6 +173,11 @@ def test_check_dimension_order(self):
         assert result.msgs[0] == ("really_bad's dimensions are not in the recommended order "
                                   "T, Z, Y, X. They are latitude, power")
 
+        dataset = self.load_dataset(STATIC_FILES['dimension_order'])
+        result = self.cf.check_dimension_order(dataset)
+        self.assertEqual((3, 3), result.value)
+        self.assertEqual([], result.msgs)
+
     def test_check_fill_value_outside_valid_range(self):
         """
         2.5.1 The _FillValue should be outside the range specified by valid_range (if used) for a variable.