Opened 10 years ago

Closed 7 years ago

#50 closed task (fixed)

Upgrade CF Checker to use CDAT-5.x and udunits2

Reported by: ros Owned by: ros
Priority: medium Milestone:
Component: cf-checker Version:
Keywords: Cc:

Description

Upgrade CF Checker to work with CDAT-5.x and udunits2

Change History (9)

comment:1 Changed 10 years ago by ros

  • Owner changed from cf-checker@… to ros
  • Status changed from new to assigned

comment:2 Changed 10 years ago by ros

source:cf-checker/branches/cdat-5.1.0/src/cfchecks-cdat-5.1.0.py r107 works with CDAT5.x and UDUNITS1

comment:3 Changed 10 years ago by ros

Used the Python module ctypes to interface to the UDUNITS2 C library as no other Python interfaces to udunits2 are available.

A couple of the udunits functions used are no longer available with udunits2, nameley utIsTime() and utCalendar()

The udunits support gave me the following substitutions:

utIsTime()
Convert the unit to seconds. All time units should be convertible with seconds and if it fails then it was not a time unit.

if(ut_are_convertible(unit,udunits.ut_parse(self.unitSystem, "second", "UT_ASCII")):

Similarly for utCalendar() try converting units to seconds with a reference time.

comment:4 Changed 10 years ago by ros

The valid units are slightly different between udunits1 and udunits2.

In udunits1 units like M/S in uppercase were acceptable. udunits2 is more fussy (accurate!) and deems M/S as an invalid unit. This will lead to some netcdf files that used to be CF-compliant being flagged as uncompliant after the upgrade.

There are, however, a few inconsistencies. METRES and DAY or Day are valid units. I've sent an email to the udunits team to report this.

comment:5 Changed 10 years ago by ros

First working version of checker with CDAT-5.2 and udunits2 lodged at revision: r109

Note that in order for the script to load the libudunits2.so library it must be in the system library path or the environment variable LD_LIBRARY_PATH must be set.

comment:6 Changed 10 years ago by ros

When udunits2 is initialised (ut_read_xml) there is a lot of verbosity.

Definition of "kt" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 86, overrides prefixed-unit "1000000 kilogram"
Definition of "microns" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 304, overrides prefixed-unit "1e-15 second"
Definition of "ft" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 401, overrides prefixed-unit "1e-12 kilogram"
Definition of "yd" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 409, overrides prefixed-unit "8.64e-20 second"
Definition of "pt" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 630, overrides prefixed-unit "1e-09 kilogram"
Definition of "at" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 1027, overrides prefixed-unit "1e-15 kilogram"
Definition of "ph" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 1545, overrides prefixed-unit "3.6e-09 second"
Definition of "nt" in "/home/ros/software/udunits2/share/udunits/udunits2-common.xml", line 1552, overrides prefixed-unit "1e-06 kilogram"

The solution, as described on the udunits mailing list (http://www.unidata.ucar.edu/support/help/MailArchives/udunits/msg00503.html) ,is to temporarily switch off printing of messages to stderr.

udunits.ut_set_error_message_handler(ut_ignore)
self.unitSystem=udunits.ut_read_xml(self.udunits)
ut_set_error_message_handler(ut_write_to_stderr)

comment:7 Changed 10 years ago by ros

Correction... calling ut_set_message_handler is not as straightforward since it takes as it's argument a pointer to a ut_error_message_handler object. See http://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2lib.html#Messages

With help from the ctypes-users mailing list the solution is to use callback functions. It also isn't possible with ctypes to deal with varargs functions. A slight cheat is needed, where we misdeclare ut_error_message_handler omitting the va_list part and use that as the signature for any functions you want to pass.

So

uemh = CFUNCTYPE(c_int,c_char_p)
ut_set_error_message_handler = CFUNCTYPE(uemh,uemh)(("ut_set_error_message_handler",udunits))
ut_write_to_stderr = uemh(("ut_write_to_stderr",udunits))
ut_ignore = uemh(("ut_ignore",udunits))

old_handler = ut_set_error_message_handler(ut_ignore)
                                           
self.unitSystem=udunits.ut_read_xml(self.udunits)

old_handler = ut_set_error_message_handler(ut_write_to_stderr)

This does the trick. No "Definition of ..." override warnings are now displayed.

r111

comment:8 Changed 10 years ago by ros

Merged cdat-5.1.0 branch into trunk.

cd cf-checker/trunk
svn merge -r 105:117 http://cf-pcmdi.llnl.gov/svn/repository-cf/cf-checker/branches/cdat-5.1.0

comment:9 Changed 7 years ago by ros

  • Resolution set to fixed
  • Status changed from assigned to closed
Note: See TracTickets for help on using tickets.