an object-oriented software system to handle bufr - Eumetsat

3 downloads 18138 Views 75KB Size Report
Sep 9, 2011 - BUFR handling software systems based on procedural lan- guages (e.g. ... Table 2: A function call used in the example program. Table 1 ...
2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

1

AN OBJECT-ORIENTED SOFTWARE SYSTEM TO HANDLE BUFR Vesa Karhila, Angeles Hernandez-Carrascal Northern Lighthouse Ltd, Reading, United Kingdom www.northern-lighthouse.com

Abstract BUFR is a meteorological code defined by the World Meteorological Organization as an alternative to traditional alphanumeric codes. It is a table-driven code form (TDCF), result of a careful design that takes into account the requirements of the meteorological communities in a world where practically all the observation processing is computer based. BUFR has many good properties, such as portability, extendibility and flexibility. BUFR is a complex code and, unfortunately, BUFR software packages often reflect that complexity on user interfaces, which makes them cumbersome and difficult to use. Object-oriented (OO) methods make it possible to create software systems that are able, on the one hand, to handle the complexity and sophistication of BUFR, and on the other, to present a clean and intuitive user interface based on high-level BUFR concepts. Information hiding, a principle deeply related to object orientation, allows to hide internal low-level complexities from module interfaces in general, and in particular from user interfaces. This paper will discuss how OO methods can be used to create such a system, and will present examples using Cipher SoftBUFR, an existing OO-based library, to show the benefits of the approach.

1

INTRODUCTION

BUFR (Binary Universal Form for the Representation of meteorological data) is a standard for the transmission and storage of meteorological observational data (Thorpe, 1994; World Meteorological Organization, 2010). It is a table-driven code form (TDCF), defined by the World Meteorological Organization (WMO) in the late 1980s, as an alternative to traditional alphanumeric codes (TAC). As the use of computers for handling observations became more generalized, the need was felt, in the meteorological community, for a single code more appropriate for computer processing than TACs. BUFR has many good properties, such as portability, extendibility and flexibility, but despite these properties, BUFR is often seen as a too complex code that requires a considerable investment of time and effort from programmers and scientists that develop BUFR applications. There is a large number of complains - the “BUFR blues” - about BUFR itself, as a code, or about specific BUFR libraries, or even about the use of BUFR by part of the meteorological community (Karhila and Hernandez-Carrascal, 2010). BUFR is a complex and sofisticated code. BUFR handling software systems based on procedural languages (e.g. Fortran or C) reflect that complexity on user interfaces, and this is the source of a large part of the problems usually perceived as associated to BUFR itself. Object-oriented (OO) methods have proved to be successful in many areas, and are well supported by several languages, including mainstream languages like C++ or Java. Certainly, there are some problems related to BUFR, e.g. misuse of BUFR tables, which no software design approach can help to overcome, but a large part of the “BUFR blues” can be tackled by appropriate approaches to software construction. This paper discusses how OO methods can be used to design BUFR handling software, giving reallife examples. Section 2 shows the problems typically derived from the use of procedural languages.

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

2

Section 3 discusses how the main OO mechanisms may contribute to write a more maintainable and user-friendly BUFR software, and gives illustrative examples from an existing OO BUFR-handling library, and section 4 concludes the paper.

2

BUFR AND PROCEDURAL APPROACH TO SOFTWARE CONSTRUCTION

The area of meteorological codes is quite abstract, and examples are very convenient in order to present issues to non-specialists. We have stated earlier that one of the main sources of the difficulties usually associated to BUFR is the complexity of APIs (Application Programming Interfaces) in non-OO BUFR libraries; in this section we will illustrate what we mean. Tables 1 and 2 show two excerpts from ECMWF BUFR software package (ECMWF, 2011), fully functional, freely available, and written in Fortran. Although Fortran90 and later standards of Fortran give some (rather limited) support for OO methods, they are not used in this library. These code snippets illustrate one of the main drawbacks of non-OO approaches: the API is very complicated and far from intuitive. IMPLICIT LOGICAL(L,O,G), CHARACTER*8(C,H,Y) C PARAMETER(JSUP = 9,JSEC0= 3,JSEC1= 40,JSEC2=4096,JSEC3= 4, 1 JSEC4=2,JELEM=320000,JSUBS=400,JCVAL=150 ,JBUFL=512000, 2 JBPW = 32,JTAB =3000,JCTAB=3000,JCTST=9000,JCTEXT=9000, 3 JWORK=4096000,JKEY=46, JTMAX=10,JTCLAS=64,JTEL=255) C PARAMETER (KELEM=40000) PARAMETER (KVALS=4096000) C DIMENSION DIMENSION DIMENSION DIMENSION DIMENSION DIMENSION

KBUFF(JBUFL) KBUFR(JBUFL) KSUP(JSUP) ,KSEC0(JSEC0),KSEC1(JSEC1) KSEC2(JSEC2),KSEC3(JSEC3),KSEC4(JSEC4) KEY (JKEY),KREQ(2) NREQUEST(2)

C REAL*8 VALUES(KVALS),VALUE(KVALS) DIMENSION KTDLST(JELEM),KTDEXP(JELEM),KRQ(KELEM) REAL*8 RQV(KELEM) DIMENSION KDATA(200),KBOXR(JELEM*4) REAL*8 VALS(KVALS) C CHARACTER*256 CF,COUT,CARG(4) CHARACTER*64 CNAMES(KELEM),CBOXN(JELEM*4) CHARACTER*24 CUNITS(KELEM),CBOXU(JELEM*4) CHARACTER*80 CVALS(kelem) CHARACTER*80 CVAL(kelem) CHARACTER*80 YENC REAL*8 RVIND REAL*8 EPS C

Table 1: Declarations used in an existing program included with the distribution of a well known procedural library.

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

3

C CALL BUFREX(KBUFL,KBUFF,KSUP,KSEC0 ,KSEC1,KSEC2 ,KSEC3 ,KSEC4, 1 KEL,CNAMES,CUNITS,KVALS,VALUES,CVALS,IERR) C

Table 2: A function call used in the example program.

Table 1 shows a code snippet from an example program shipped with the mentioned software package, showing the declarations which an application programmer needs to write before any functional code: the meaning of these declarations is anything but clear, and it is actually the first step in writing an application that uses the library! Table 2 shows one function call, with 15 arguments, from the same example program. The snippets shown are not yet a working program; a real-life application program would need to call several functions with similarly long, complicated and unintuitive interfaces. The characteristics of the task make it a challenge for users, and not surprisingly are a source of low motivation, low productivity, misinterpretations and errors, and give BUFR a bad reputation. Debugging and maintaining application programs is a truly challenging task. In our view, BUFR should be a challenge for BUFR software designers, not for its users. BUFR is a sophisticated code, with many good characteristics. However, the use of non-OO software systems brings unnecessary complexity to the development and maintenance of applications.

3

BUFR AND OBJECT-ORIENTED APPROACH TO SOFTWARE CONSTRUCTION

This section will discuss how some key OOP (Object-Oriented Programming) elements and mechanisms can contribute to the construction of quality software to handle BUFR, and will show examples using Cipher SoftBUFR, an existing OOP-based library for handling BUFR, of how these mechanism can be used in practice. For a detailed presentation of OOP elements, principles and mechanisms, readers are referred to e.g. Booch et al. (2007), Meyer (1997) or Stroustrup (1997). 3.1

Classes and Objects

Class is a central concept in OOP, and it has two meanings: 1) it is an abstraction that serves to describe the properties of certain type of objects e.g. BUFR section 1, and 2) it is a software module where these properties are implemented, either as data or as functions that act on objects of that class. The two meanings of the word are usually distinguishable by the context. In a way, classes are like data types in procedural languages, but they can be much more sophisticated, and therefore more powerful. Some examples of classes in Cipher SoftBUFR are: • VBufrSource - a class for representing a file containing BUFR messages. It contains all the data and methods (functions) needed to extract BUFR messages from a file. • VBufrObs - a class for representing one observation report. It contains data and functions needed to extract or add data from/to BUFR messages. • VBufrData - a class for representing individual BUFR data element. It contains all data and methods needed to read data from, or to write data to BUFR messages, to display the data and its properties, to compare and to compute with it... • VBufrTime - a class for representing date/time information. It contains all data and methods to read date/time info from, or write date/time info to BUFR messages, to display it, to compare it,...

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

4

Object, another key concept in OOP, can also be used with different meanings. Although some times it is used to refer to real-world items, in OOP “object” often means an instance of a class. Objects in this sense can be seen as the (sophisticated) counterpart of variables in procedural languages. Table 3 shows some examples of how objects can be declared in SoftBUFR.

VBufrObs myObs; //-- myObs is an object of class VBufrObs. VBufrSource mySource(‘‘filename’’); //-- mySource is an object of class VBufrSource, //-- initialised with the given file VSmartBufrData myData(12163); //-- myData is an object of class VSmartBufrData, //-- initialised to represent brightness //-- temperature (using BUFR descriptor 0’12’163)

Table 3: Code snippet showing examples of object declarations in applications using SoftBUFR.

Objects contain the data that describe them, and therefore function calls normally have very few arguments, if any. Table 4 shows some examples of function calls using examples from SoftBUFR. The last example in the table illustrates how powerful the OO approach is: the programmer does not need to declare any variables to access the metadata of the observation. As the metadata are part of the objects of class myObs, they can be accessed through function msgMetaData() when needed.

n = myObs.descriptorCount(12163);

//-//-//-v = myData.value(); //-//-s = myData.unit(); //-//-i = myObs.msgMetaData().msgType(); //-//--

returns how many times brightness temp 0’12’163 is found in the observation report associated to object myObs returns the numeric value of data element myData returns a string containing the unit of data element myData returns the code for message type from the metadata of myObs

Table 4: Examples of function calls using examples from SoftBUFR.

3.2

Information Hiding

Information hiding (or encapsulation) is the ability to prevent certain aspects of a class from being accessible to its clients (Meyer, 1997). These aspects may be data or functions, and the access level is set explicitely in the class module. There is a neat division between the part of a class that is available to other software modules, and that represents the services offered by the class, and the part that is not accessible to clients and is typically related to implementation details. Table 5 shows an example of information hiding, taken from class VBufrObs from SoftBUFR. Clients of the class have no access to msg and iteratorInitialised variables, but have access to msgMetaData(). 3.3

Inheritance

Inheritance is a mechanism whereby a class is defined in reference to others, adding all their features to its own (Meyer, 1997). This mechanism is essential in the design of the structure of OO class libraries,

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

5

class VBufrObs { ... private: VBufrMsg* msg; bool iteratorInitialised; ... public: VBufrMetaData msgMetaData(){ return msg->msgMetaData(); } ... };

Table 5: SoftBUFR example: code snippet from VBufrObs class definition illustrating information hiding.

and it helps to reuse and maintain code. Perhaps it is more important for developers of software libraries than for developers of applications that use those libraries. Like with information hiding, if it well applied, users are not aware of it. Table 6 shows an example of inheritance relations between classes from SoftBUFR. Function unit is defined in class VBufrData. Class VSmartBufrData is descendant of VBufrData, so unit, even when not explicitly shown in the class definition, it is available to VSmartBufrData. Function isPartOf is virtual and it has different implementations in these two classes.

class VBufrData { ... public: vString unit(); virtual bool isPartOf( VBufrObs& anObs ); ... }; class VSmartBufrData : public VBufrData { ... public: virtual bool isPartOf( VBufrObs& anObs ); ... };

Table 6: Example of inheritance from SoftBUFR.

3.4

Polymorphism, Dynamic Binding, and Overloading

Polymorphism is the ability for an element of the software text to denote, at run time, objects of two or more possible types. Dynamic binding guarantees that every execution of an operation will select the correct version of the operation, based on the type of the operation’s target (Meyer, 1997). It often happens that several similar classes, related through inheritance links, have slighly modified implementations of an inherited function (e.g. a write or get date). The operations are actually slightly different, although they share the same function (or method) name. Dynamic binding ensures the correct selection at run-time.

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

6

Table 7 shows an example from SoftBUFR class library, illustrating polymorphism. VBufrTarget is a class that represents a target BUFR file which will contain single-subset BUFR messages. VBufrTarget encodes VBufrObs objects while writing them to the target file. Class VBufrCompressedTarget is a descendant of VBufrTarget, and it represent compressed multi-subset BUFR messages. It inherits all the functionality of VBufrTarget and re-implements “encode-while-you-write” functionality by temporarily storing observation reports in order to build compressed multisubset messages.

VBufrTarget *myTarget; // myTarget is a pointer to an object of class VBufrTarget if (makeCompressed) myTarget = new VBufrCompressedTarget(‘‘filename’’,50); else myTarget = new VBufrTarget(‘‘filename’’); *myTarget >’’ reads one BUFR report/subset from a file // here ‘‘>>’’ reads/extracts brightness temp from report

n = myObs.descriptorCount();

// returns total number of element // descriptors in myObs n = myObs.descriptorCount(12163);// returns num of 0’12’163 descriptors in myObs

Table 8: Code snippet illustrating overloading.

Table 8 shows an example illustrating function and operator overloading with examples using SoftBUFR. The “read” operator (“>>”) can be applied to different types of objects, and has a different behaviour,

2011 EUMETSAT Meteorological Satellite Conference, Oslo, Norway, 5-9 September 2011

7

depending on the object it is applied to. Method descriptorCount() of class VBufrObs has different behaviour depending on the argument types. In each case, as there are differences in the interfaces, the compiler can select the appropriate operation. Note that the example in table 7 is not an example of overloading: the compiler would not be able to select the right operation as there are no differences in interfaces. The ambiguity in that case is solved at run-time by dynamic binding. 3.5

OO Approach: Putting the Pieces Together

Table 9 shows a small BUFR application based on SoftBUFR class library. The program reads the first BUFR message from a file, extracts the date and time and the first brightness temperature in the message, and finally prints the extracted values. This is a fully working program which can be compiled and run. When run with a proper BUFR file it would print something like 277.19K 2011-09-07 16:45.

#include ‘‘softbufr.h’’ int main() { VBufrSource myFile(‘‘fname’’); VBufrObs myObs; myFile >> myObs; VSmartBufrData myBT(12163); VBufrTime myTime; myObs >> myBT >> myTime;

// include SoftBUFR header file // create a BUFR file object // create a BUFR report object // read one BUFR report // create a brightness temperature data object // create a date/time data object // ‘‘read’’ the data from the BUFR report

cout