Thursday, 6 October 2011

Calling routines from the NAG Fortran and C libraries from within LabVIEW

This is a follow-on from my colleague Sorin Serban's recent post, in which he looked at invoking methods from the NAG Library for .NET from within the LabVIEW programming environment. The motivation for this work was the realization that many LabVIEW users want to enhance their applications by making use of some of NAG's numerical routines. Recently, I've been using our Fortran and C libraries to do the same thing, and some of this work is discussed here.

The mechanism used within LabVIEW to call a routine from either of these libraries is different from that used in the case of the .NET Library. This is because that library is a so-called .NET assembly, whilst the C and Fortran libraries are (on the Windows platform) dynamic link libraries (DLLs). The .NET assembly uses the common language runtime (CLR) and the .NET framework to manage assembly functions, and to export information about classes, methods, properties and events. The practical implication of this is that when a method from the NAG Library for .NET is loaded into LabVIEW, information about its function arguments is automatically loaded as well. This is not the case with a DLL, as we shall see.



As previously, we begin building a LabVIEW application by creating a blank virtual instrument (VI) using, for example, the Blank VI option on LabVIEW’s Getting Started splash screen, and go to the block diagram, which is where our routine will be loaded. Once again, we build our example around the NAG routine g01aa, which performs simple statistical calculations on a set of ungrouped data; besides being implemented as a method in the .NET Library, it is also available in both the Fortran and the C libraries.

To load the routine, we first bring up the Functions Palette, using the option on the View menu on the block diagram window. Next, we open the Connectivity collection from the palette, and then the Libraries & Executables item. This palette contains a variety of functions for calling code from libraries and executing system commands, and we select the Call Library Function item – which calls a DLL directly – and drag it onto the block diagram in order to initialize it. To specify the library we want to call, we right-click on the node and select Configure.... This brings up the Call Library Function dialog box, and we enter the name of the DLL in the Library name or path box. In general, either the name or the path is acceptable, although the choice between between them has consequences if the VI is to be distributed or relocated. In our example, we're running LabVIEW under Windows, and are using the implementation of the NAG Fortran Library contained in FLDLL224M_nag.dll and the NAG C Library implementation in CLW3209DA_nag.dll.

Having specified the library, we next select the name of the routine we wish to call by picking it from the drop-down list in the Function name dialog box; in our example, this is G01AAF if we're using the NAG Fortran Library, or g01aac if it's the NAG C Library that we're calling. In either case, we specify the calling convention as stdcall (WINAPI).

The next step is to tell LabVIEW about the argument list for our routine via the Parameters tab on the Call Library Function dialog box. For each parameter, we specify its name, type and how it is to be passed (as a value or a pointer to a value) to LabVIEW when it calls the routine. As these details are entered, LabVIEW updates the Function prototype display at the bottom of the dialog box with the C prototype of the routine (LabVIEW is written in C, and it is from this language that the external routine is called). This table shows the parameters for G01AAF, including their Fortran type, their LabVIEW specification and the C type that LabVIEW generates for the function prototype:

Fortran variable nameNAG Fortran typeLabVIEW TypeLabVIEW Constant?LabVIEW Data typeLabVIEW PassLabVIEW Array FormatLabVIEW C type
NINTEGERNumericYSigned 32-bit IntegerPointer to Value-const int32_t*
Xdouble precision arrayArrayY8-byte Double-Array Data Pointerconst double*
IWTINTEGERNumericNSigned 32-bit IntegerPointer to Value-int32_t*
WTdouble precision arrayArrayN8-byte Double-Array Data Pointerdouble*
XMEANdouble precisionNumericN8-byte DoublePointer to Value- double*
S2double precisionNumericN8-byte DoublePointer to Value- double*
S3double precisionNumericN8-byte DoublePointer to Value- double*
S4double precisionNumericN8-byte DoublePointer to Value- double*
XMINdouble precisionNumericN8-byte DoublePointer to Value- double*
XMAXdouble precisionNumericN8-byte DoublePointer to Value- double*
WTSUMdouble precisionNumericN8-byte DoublePointer to Value- double*
IFAILINTEGERNumericNSigned 32-bit IntegerPointer to Value-int32_t*

Although there are several parameters, many of them have the same characteristics. Firstly we recall that, since Fortran passes arguments by reference (not by value), each parameter must be passed as a pointer when calling the Fortran routine from LabVIEW (i.e. from C). Next, the documentation for this implementation of the NAG Fortran Library tells us that double precision means DOUBLE PRECISION - that is, an 8-byte floating point number, whilst the Fortran INTEGER type is a 32-bit integer. Hence, these two types can be respectively mapped to double and int32_t, via LabVIEW's 8-byte Double and Signed 32-bit Integer types. Finally, it can be seen how designating a variable as a constant (because it's only used on input to the routine) results in LabVIEW applying the const qualifier to the C type.

Similar remarks apply, for the most part, to the use of the g01aac routine (note that the parameter list is slightly different for this version of the routine):

C variable nameNAG C typeLabVIEW TypeLabVIEW Constant?LabVIEW Data typeLabVIEW PassLabVIEW Array FormatLabVIEW C type
nIntegerNumericYSigned 32-bit IntegerValue-const int32_t
xconst double arrayArrayY8-byte Double-Array Data Pointerconst double*
wtconst double arrayArrayY8-byte Double-Array Data Pointerconst double*
nvalidInteger*NumericNSigned 32-bit IntegerPointer to Value-int32_t*
xmeandouble*NumericN8-byte DoublePointer to Value-double*
xsddouble*NumericN8-byte DoublePointer to Value-double*
xskewdouble*NumericN8-byte DoublePointer to Value-double*
xkurtdouble*NumericN8-byte DoublePointer to Value-double*
xmindouble*NumericN8-byte DoublePointer to Value-double*
xmaxdouble*NumericN8-byte DoublePointer to Value-double*
wsumdouble*NumericN8-byte DoublePointer to Value-double*
failNagError*NumericNSigned 32-bit IntegerValue-int32_t

Since we're now calling a C routine from C, there is a closer correspondence between the NAG type and the LabVIEW C type, although a couple of additional explanatory remarks might be necessary. Firstly, the NAG C Library uses a data type called Integer; for this implementation, this is defined as long, which is a 32-bit integer on Windows systems. Secondly, the fail variable is a pointer to a C structure named NagError; we access this using a 32-bit integer (not a pointer to an integer), which is the same size as the address of the structure.

More information about how to create an interface between LabVIEW and external libraries (including advice for more complicated cases than those used here) is available here. Having created the interface to the NAG routine, the final step is to add LabVIEW controls and indicators to handle the input and output of our application. This is exactly the same procedure as was described previously, and we conclude this post with Figure 1, which shows the block diagram of our application, centered around the Call Library Function, which is where the NAG routine (in this case, g01aac) is being called.

4 comments:

  1. This is an excellent introduction to calling NAG Fortran and C routines from LabVIEW.

    For me the key difference between the two libraries is how they handle fail conditions. The fortran routines pass a single integer value which determines how an error will be handled (hard or soft fail), and receives the error code on completion of the routine. Control of error handling with the C library functions requires the passing of C structures which is not at all straightforward from LabVIEW.

    In principle, calling C routines from LabVIEW appears to be straightforward as LabVIEW follows many of the C conventions. However, as long as the differences between Fortran and C, such as the handling of strings and array are kept in mind both are reasonable easy to handle from LabVIEW. I've written more details on this here.

    The above link also contains some hints on making the LabVIEW interface to the NAG libraries more readable, such as displaying terminal names in the call library function node and grouping similar input or output nodes together in clusters.

    ReplyDelete
  2. Many thanks for the helpful comment, Conway, and for the pointer to your article which contains a wealth of further useful information on this topic. Your main point here about the difference between calling the Fortran and C libraries from LabVIEW is, I think, well-taken: as noted, I used an integer for the address of the C structure. This satisfies the requirements of the calling protocol, but it's not possible (or at least, much more difficult) to make any use of the contents of the structure - i.e. we can't check for any error conditions.

    ReplyDelete
  3. Following this description of how to call NAG routines from LabVIEW, I've written some examples illustrating some aspects of this work. They're now available for download from our LabVIEW page which contains a link to an archive containing eighteen LabVIEW examples that use a variety of NAG routines and methods.

    ReplyDelete
  4. You might like to know that I gave a presentation about enhancing LabVIEW using NAG Library routines earlier this week; the slides are available for download from our LabVIEW page and provide a self-contained account of how to do this (including a couple of specific example applications which use NAG routines), together with a description of how to construct a wrapper library around selected NAG functions, and then import that into LabVIEW.

    ReplyDelete

NAG moderates all replies and reserves the right to not publish posts that are deemed inappropriate.