PDBLib User’s Manual

Portable Data Base Library

Stewart A. Brown
Al Franz


Introduction

PDBLib Design Philosophy
PDBLib API Overview
PDBLib and Index Ordering
PDBLib and Index Offsets
Compiling and Loading
Memory Management Considerations
PDB Syntax
PDBLib Rules
PDB File Format
Terms
Data Conversion and Compression

Using PDBLib

Functions in each group are listed in functional order.
o indicates functions that are mandatory or nearly so
o indicates functions for optional use

Opening, Creating, Closing, and Controlling PDB Files
o PD_SET_BUFFER_SIZE
o PD_TARGET
o PD_OPEN
o PD_ACTIVATE_CKSUM
o PD_VERIFY
o PD_AUTOFIX_DENORM
o PD_FIX_DENORM
o PD_SET_FORMAT_VERSION
o PD_SET_MAJOR_ORDER
o PD_SET_MAX_FILE_SIZE
o PD_SET_OFFSET
o PD_FAMILY
o PD_FLUSH
o PD_CLOSE
Writing Data to PDB Files
o PD_WRITE
o PD_WRITE_ALT
o PD_WRITE_AS
o PD_WRITE_AS_ALT
o PD_APPEND
o PD_APPEND_ALT
o PD_APPEND_AS
o PD_APPEND_AS_ALT
Reserving Space for Future Write
o PD_DEFENT
o PD_DEFENT_ALT
Reading Data from PDB Files
o PD_READ
o PD_READ_ALT
o PD_READ_AS
o PD_READ_AS_ALT
Defining New Data Types
o PD_CAST
o PD_DEFIX
o PD_DEFLOAT
o PD_DEFNCV
o PD_DEFSTR
o PD_DEFSTR_ALT
o PD_TYPEDEF
Defining Attributes
o PD_DEF_ATTRIBUTE
o PD_GET_ATTRIBUTE
o PD_REM_ATTRIBUTE
o PD_SET_ATTRIBUTE
Queries
o PD_GET_BUFFER_SIZE
o PD_GET_ERROR
o PD_GET_FILE_LENGTH
o PD_GET_FILE_NAME
o PD_GET_FORMAT_VERSION
o PD_GET_MAX_FILE_SIZE
o PD_GET_MAJOR_ORDER
o PD_GET_MODE
o PD_GET_OFFSET
o PD_QUERY_ENTRY
o PD_GET_ENTRY_INFO
o PD_FREE_ENTRY_INFO
o PD_INQUIRE_TYPE
o PFIMBR
Using Pointers
o PD_GET_TRACK_POINTERS
o PD_SET_TRACK_POINTERS
o PD_RESET_PTR_LIST
o PD_FREE
Using Directories
o PD_CD
o PD_LN
o PD_LS
o PD_LS_ALT
o PD_MKDIR
o PD_PWD
Parallel Programming with PDB
o PD_INIT_THREADS
o PD_INIT_MPI
o PD_TERM_MPI
o PD_MP_OPEN
o PD_MP_CREATE
Special Purpose I/O
o PD_PUT_IMAGE
o PD_PUT_MAPPING
o PD_PUT_SET
o PD_MAKE_IMAGE
o PD_REL_IMAGE
o PFWRAN

Data Structures in PDBLib

DATA_ALIGNMENT
DATA_STANDARD
DEFSTR
DIMDES
MEMDES
PDBFILE
SYMENT

PDBLib by Example

Working with PDB files
Writing Data to PDB files
Reading Data from PDB files
Appending Data to PDB file variables
Inquiries in PDBLib
Browsing PDB files
Writing PM_mappings with PFWMAP
Writing PM_mappings with PFWSET and PFWRAN
SMP Parallel Example
MPI Parallel Example

Related Documentation


Introduction

PDBLib is a small library of file management routines useful for storing and retrieving binary data in a portable format. It is intended to supply a flexible means of managing binary databases without the user having to be concerned with the machines on which they are written or read. Please note that PACT headers MUST be included before all other headers. See the SCORE introduction for more information.

The specific goals for this library are:

PDBLib Design Philosophy

Perhaps the most fundamental element in the design of PDBLib is the concept of modularity through abstraction barriers. In essence, the functionality is broken down into modular units and abstraction barriers are used to preserve the integrity of the units.

An abstraction barrier is simply a technique or device which allows a section of code to be written assuming other functions or routines are defined and that their internal workings are irrelevant to their use. In this way a routine or module can be changed without any other part of the code which uses it being affected (so long as the definition of its function does not change). Abstraction barriers are most effectively created by a careful choice of the basic functional units and by the interfaces between them.

For example, if all variables in the code were global there would be little or no chance of having any abstraction barriers at all. Similarly, monolithic functions which are defined to `solve the worlds problems' do not lend themselves to the more easy maintenance that abstraction barriers afford a program. For a good discussion of the principles and applications of these ideas see Abelson and Sussman's marvelous book, The Structure and Interpretation of Computer Programs.

The main functional units in the PDBLib system are: the hash package which controls the maintenance of the data in both the symbol table and structure chart; the conversion package which handles all data format conversions; the data reading routine which is defined to bring data in from the disk, perform any necessary conversion, and store it in the specified location(s) of memory; and the data writing routine which does the reverse of the reading routine.

These units are put together in such a way that they are used over and over again in the process of doing any of the high level functions. In this way the code size was kept relatively small. Again this is one of the rewards of modularity.

Overview of PDBLib API

The functional PDBLib interface was designed as a minimal extension of the standard C library binary I/O interface. The relevant C library functions are fopen, fclose, fwrite, and fread. The extensions are driven mainly by some missing features in C. Because C doesn't handle data types as types, PDBLib must be told the type of a variable when it is written to a file. Because C variables don't know about their dimensions, PDBLib must be given the dimensions when a variable is written out. On the other hand, because PDBLib knows both type and dimension information about file variables, PDBLib requires less information from the programmer when reads are done.

Since C doesn't have the needed type handling facilities, data structures must be described to PDBLib. Therefore, in addition to the basic I/O functions mentioned above, there is a function in PDBLib to be used when a C data structure or a FORTRAN common block must be described in a file.

Next, to give the user the most flexibility and efficiency regarding data conversions, PDBLib has a function which lets the user specify the binary data format of the file. In this way, a file can be targeted for a particular machine type. A common use for this might be when a powerful machine produces some data which is going to be reprocessed on a less powerful machine. The more powerful machine which writes the file might target the file for the less powerful one so that the conversions are done by the faster machine and not the slower one.

In some applications with structures, some members of a structure may be pointers, and the actual type to which a pointer points may be changed by a cast depending on some other member's value. PDBLib supports the notion of a "cast" in that it can be told to ignore the type of a structure member and get the actual type from another member when it writes out the structure.

There are also routines to manage data attributes. An attribute table will be created for a PDB file the first time PD_def_attribute is called. The attribute table is kept in the PDBfile structure. Variables can be added to PDB files solely for their attribute values. Attributes can be given to entire variables or any part of them. This works because the attribute table is a separate hash table, like the symbol table, which associates names with attribute values. It also is used to manage the attributes themselves. It is not exactly clear why one should use these attributes. Most of the utility of attributes is already inherent in the structures or records which can by built with PDBLib's mechanism for defining derived types. Since the structure handling mechanisms are much more efficient, the reason for using attributes instead of structures should be very clear in the mind of the application programmer.

Because all of the information about files and their contents is contained in PDBLib structures and hash tables, the C API (Application Program Interface) has no inquiry functions. Users can extract information directly from the PDBfile structure and they can use the hash table lookup function, SC_def_lookup, to get access to the syment and defstr structures which describe variables and types, respectively.

The FORTRAN API to PDBLib has most of the same functions as the C API. There are some differences due to the differences in the languages.

SX, a version of the SCHEME programming language with extensions for PACT, has a PDBLib API. In fact, PDBView is largely an SX program which means that it is immanently suited to user customization. The SX interface to PDBLib is largely documented here. More documentation may be found in other PACT manuals.

A Python module is also available to access PDBLib's functionality.

PD_GET_FORMAT_VERSION

C Binding:   void PD_get_format_version(int v)
F77 Binding: integer PFGFMV(integer v)
SX Binding:  (format-version)
Python Binding:  XXX - missing

Get the format version to be used when creating new PDB files to v. See the section PDB File Format for a discussion of the PDB file formats.

Input to this function is: v, an integer in which to return the format version.

In the C binding return the value of the format version. In the FORTRAN binding return 1 if successful, 0 otherwise.


C Example
       int v;
             .
             .
             .

       PD_get_format_version(v);
             .
             .
             .

Fortran Example
       integer pfgfmv
       integer v
             .
             .
             .

       v = 3
       if (pfgfmv(v) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (format-version)
             .
             .
             .

Python Example
             .
             .
             .

PDBLib and Index Ordering

Languages such as C and FORTRAN differ about the major ordering of arrays. For example, C is row major and FORTRAN is column major. To accommodate the use of PDB files among applications in different languages, each PDB file contains a flag that says which ordering to use.

The C header file #define's two constants:

   #define ROW_MAJOR_ORDER     101
   #define COLUMN_MAJOR_ORDER  102
These values define how PDB treats index expressions when reading and writing data. PDB does NOT transpose arrays when reading or writing, it transposes the index expressions.

By default PDB files created via the C interface are set with ROW_MAJOR_ORDER and files created via the FORTRAN interface are set with COLUMN_MAJOR_ORDER. Applications can query or change the value at any time after the file is opened/created. See the functions PD_SET_MAJOR_ORDER and PD_GET_MAJOR_ORDER.

Using PDBView you can check the mode of a given file using the file command.

We recommend that when you know that you will be using files between applications in different languages that you use column major ordering consistently. There is no deep reason for this. It simply helps you to be consistent and to have an expectation of how to think about your files.

PDBLib and Index Offsets

Languages such as C and FORTRAN differ about the default value for the first index value in an array. For example, C uses 0 based indexing and FORTRAN uses 1 based indexing. To accommodate the use of PDB files among applications in different languages, each PDB file contains a flag that specifies the default offset.

The offset determines how PDB treats index expressions when reading and writing data. It doesn't affect the number of items specified by a dimension. It only affects the range of index values.

By default PDB files created via the C interface are set with a default offset of 0 and files created via the FORTRAN interface have a default offset of 1. Applications can query or change the value at any time after the file is opened/created. The value can be set to any integer value so it is more general than would be strictly necessary if there were only C and FORTRAN. See the functions PD_SET_OFFSET and PD_GET_OFFSET.

Using PDBView you can check the default offset of a given file using the file command.

Compiling and Loading

To compile your C programs you must use

 #include <pdb.h>
in the source files which deal with the library.

To link your application you must use the following libraries in the order specified.

-lpdb -lpml -lscore [-lm ...]
Although this is expressed as if for a UNIX linker, the order would be the same for any system with a single pass linker. The items in [] are optional or system dependent.

Each system has different naming conventions for its libraries and the reader is assumed to understand the appropriate naming conventions as well as knowing how to tell the linker to find the installed PACT libraries on each system that they use.

Memory Management Considerations

PDBLib is capable of correctly handling data that is indirectly referenced through arbitrary levels of pointers. In order to do this it is necessary to put an extra layer of memory management over the standard C library routines. The basic requirement is that given a pointer, one would like to know how many bytes of data it points to. The functions, SC_alloc, SC_realloc, SC_strsave, SC_free, and SC_arrlen, built on top of the standard C library functions, malloc and free, provide this capability. For C programmers, macros are provided which offer a nice and intuitive way of using these functions (they also provide an abstraction barrier against the details of any memory management scheme). These functions and macros are documented in the SCORE User's Manual.

A brief discussion of the procedure for writing and reading indirectly referenced data follows. Although the discussion will use integers as an example, the ideas apply to all data types, primitive or derived.

Consider the following:

int a[10], *b;

b = MAKE_N(int, 10);

Both a and b are pointers to 10 integers (macro MAKE_N is used to allocate the necessary space). The difference as far as an application is concerned is that the space that a points to was set aside by the compiler at compile time (for all practical purposes) while the space the b points to is created at run time. There is no possibility, given the definition of the C language, of asking the pointer a how many bytes it points to. On the other hand, since b is dynamically allocated, an extra layer of memory management could be provided so that a function, SC_arrlen, could be defined to return the number of bytes that a dynamically allocated space has. In particular,

SC_arrlen(a) => -1 (indicating an error)

SC_arrlen(b)/sizeof(int) => 10

SC_arrlen(b+5) => -1 (indicating an error)

These functions and macros can be found in SCORE. The general utility of something like SC_arrlen made it desirable to put it in the lowest possible level library. This could be used, for example, to implement some dynamic array bound checking.

PDBLib uses this idea to be able to trace down arbitrary layers of indirection and obtain at each level the exact number of bytes to write out to a file. Of course, it also writes this information out so that the correct amount of space can be allocated by read operations as well as re-creating the correct connectivity of data structures.

Great care must be taken that pointers to fixed arrays not be embedded in a chain of indirects unless their dimension specifications are included either in the I/O request or the definition of a structure. This point cannot be over-emphasized! The extra memory management layer may fail to detect a statically allocated array and return an erroneous byte count. This in turn will cause very obscure incorrect behavior (in the worst of circumstances) or a direct crash (the best outcome possible).

Also, note that subsets of dynamically allocated arrays cannot know how many bytes they contain and hence care should be taken in their use.

The example on the following page shows the different ways that statically allocated arrays, dynamically allocated arrays, statically allocated arrays of pointers, and dynamically allocated arrays of pointers are handled by PDBLib. Note: The function SC_strsave invokes the MAKE_N macro.

 /* define variables in pairs - one to write and one to read into */
    PDBfile *strm;
    char *a, *b;
    char c[10], d[10];
    char *e[3], *f[3];
    char **s, **t;

    s = MAKE_N(char *, 2);

/* fill statically and dynamically allocated arrays */
    strcpy(c, "bar");
    a = SC_strsave("foo");

/* fill statically and dynamically allocated arrays of pointers */
    e[0] = SC_strsave("Foo");
    e[1] = NULL;
    e[2] = SC_strsave("Bar");
    s[0] = SC_strsave("Hello");
    s[1] = SC_strsave("world");

/* write these variables out
 * note the dimension specifications and the type
 */
    PD_write(strm, "c(10)", "char", c);
    PD_write(strm, "a", "char *", &a);
    PD_write(strm, "e(3)", "char *", e);
    PD_write(strm, "s", "char **", &s);

/* read the file variables into fresh memory spaces
 * note that the pointers to the pointers are passed in since the
 * space is to be allocated and the value of the pointer here must
 * be set to point to the new space
 */
    PD_read(strm, "c", d);
    PD_read(strm, "a", &b);
    PD_read(strm, "e", f);
    PD_read(strm, "s", &t);

PDB Syntax

This section contains discussion of some PDB concepts that are used elsewhere in this manual.

In the following discussion and elsewhere in the manual a BNF style notation is used. In such places the following constructs are used:

| or
[] items between the brackets are optional
[]* zero or more instances of the items between the brackets
[]+ one or more instances of the items between the brackets
"x" literal x Since a data entry can be of a structured type, in general, a data entry is a tree. A part of the data tree is specified by a path to that part. A path specification is of the form:

path := node_spec | path.node_spec
node_spec := name["[" index_expr "]"]* | name["(" index_expr ")"]*
name := entry-name | member-name

The last node specified is referred to as the terminal node.

PDBLib Rules

There are a few crucial rules to be followed with PDBLib. If they are not obeyed, PDBLib may crash or the results desired will not occur.

Rule #1

The following reserved characters or sequences are not allowed in variable names or defstr member names:
'.',  '(',  ')', '[',  ']'  and  '->'.
They are reserved by the grammar of the data description language which follows some C and some FORTRAN conventions. It is recommended that you try to be somewhat conservative in choosing identifier names. Some punctuation characters are perfectly legal to use but may cause confusion when browsing files or reading your own code.

Rule #2

In each read and write operation, the type of the argument corresponding to the variable to be written or read must be a pointer to an object of the type specified for the entry. For example,

     int *a, *b;
            .
            .
     PD_write(strm, "a", "integer *", &a);
     PD_read(strm, "a", &b);
            .
            .

Rule #3

When using pointers and dynamically allocated memory with PDBLib, use SC_alloc, SC_realloc, SC_strsave, MAKE, MAKE_N, REMAKE, or REMAKE_N to allocate memory. These functions and macros are documented in the SCORE User's Manual.

Rule #4

When reading or writing part of a variable, especially a structured variable, the terminal node must be of primitive type or a structure containing no indirections and whose descendant members contain no indirections. Furthermore, the path to the desired part must contain one array reference for each level of indirection traversed. For example,
     char **s, c;
 
 /* fill s so that s[0] = "Hello" and s[1] = "World" */
            .
            .
     PD_write(strm, "s", "char **", &s);
 
 /* read the `o' in "Hello" */
     PD_read(strm, "s[0][4]", &c);
 
 /* read the `o' in "World" */
     PD_read(strm, "s[1][1]", &c);
            .
            .

PDB File Format

Up until PDBLib version 19 the file format has gone through only one major revision. These two formats were deeply connected to the internal workings of PDBLib itself. As such those file formats were not documented. Over the years certain problems and experience have led to the design of a next generation PDB file format. This is the third file format version for PDB. Its design addresses three main goals:

1) Total separation of data and metadata.

Earlier versions of the PDB file format had metadata at the beginning and end of the file. If pointers were written, there was metadata interspersed amidst the data itself.

With the new format, all PDB metadata is concatenated at the end of the file, including pointer metadata. This means that PDB metadata can be attatched to the end of any file rendering it a valid PDB file. A simple extension of this will permit the metadata to exist in a separate file. This design strategy opens the door to greater flexibility in using PDBLib to access arbitrary data files. It also promises benefits in dealing with data files in parallel applications.

2) More efficient operation.

The organization of the metadata improves on the scheme used in earlier versions. Earlier versions introduced a metadata section seperate from the structure chart and symbol table called the extras. The extras provide a means to accrete new features into PDBLib without invalidating existing files.

Several extras dealt with extentions to the description of the data types. This led to a requirement that the extras had to be read in order to interpret the data types correctly. The new format generalizes this idea to make the description of data types more extensible and remove any data type description elements from the extras. In effect, this gives data types their own independent extras. This in turn means that the interpretation of the type metadata is self contained and in a way that can be extended in the future.

The structure chart has been broken down into two distinct sections for: primitive types and compound types. The syntax of these sections has been refined for their respective needs.

The new design for handling pointers improves I/O performance by reducing the amount of seeking around on disk to find the pointer metadata. All of the pointer metadata is contained in the /&ptrs directory of the symbol table. As such the pointers are able to be processed using more of the general PDBLib functionality and require less specialized coding.

3) Human readable and editable.

The new design of the metadata section features 100% ASCII representation of the information. A syntax for the metadata was chosen to make the metadata more human readable. Also, where possible the elements of C language syntax were used in order to make the metadata more intuitive to users familiar with that language.

Occassionally, file system errors corrupt data files. By redesigning the metadata section to be both ASCII and as human readable as possible, the goal is to make it as easy as possible for a user, program or shell script to repair files which have damaged metadata.

Also to fully realize the potential of having separated the metadata into a single, complete section, it makes sense to have it human readable. A person has a higher probability of composing a description of some pure binary file and turning it into a PDB file with this design. A script or a program to do this becomes relatively simple in comparison to the previous PDB formats. By emphasizing the human readability and comprehensibility of the metadata, the entire PDBLib machinery becomes even more accessible for a wider range of applications.

In order to meet these goals (especially goal 3) it is imperative that the format of the metadata be documented. You can also use a text editor such as emacs to look at a PDB file. If you peruse the end of a format version I or II file you will recognize some elements of those formats. If you look at the end of a format version III file you will plainly see the metadata spelled out.

The current default is to write format version II files. This is a transitional measure to allow users to become familiar with format version III. An application can select which format version to use when creating new PDB files. See the PD_set_format_version routine for details.

Format Version III Syntax

A) PrimitiveTypes

The primitive data types are perhaps the most fundamental of all the metadata. The compound types are defined in terms of primitive types and other compound types. The symbol table cannot be interpreted without understanding the types.

The metadata section for the primitive types starts with a line containing only the tag, "PrimitiveTypes:". Each primitive type is defined by a single line of the form:

      <type> <Nbytes> <alignment> <attributes>;
where
      <type>       := the name of the data type, e.g. int
      <Nbytes>     := the length in bytes of an instance of the type
      <alignment>  := the byte alignment of the type
      <attributes> := <attribute>[|<attribute>]*
      <attribute>  := <order> | FIX | <float> | NO-CONV | UNSGNED |
                      <typedef> | ONESCMP
      <order>      := ORDER(<ord-spec>)
      <ord-spec>   := big | little | <Nbytes comma delimited integers>
      <float>      := FLOAT(<float-spec>)
      <float-spec> := #bits,#exponent-bits,#mantiss-bits,offset-sign-bit,
                      offset-exponent-field,offset-mantisssa-field,
                      leading-bit-flag,exponent-bias
      <typedef>    := TYPEDEF(<type>)
Three other fundamental pieces of information exist with the primitive types:
      StructAlignment    - additional alignment for structs
      DefaultIndexOffset - the value of the default array index offset
                           typically 0 for C codes and 1 for Fortran
      MajorOrder         - the major ordering for multi-dimensional arrays
                         - typically "row" for C and "column" for Fortran
The following excerpt from an actual file illustrates:
      PrimitiveTypes:
         *          4   4  ORDER(little)|FIX;
         char       1   1  NO-CONV|FIX;
         int        4   4  ORDER(little)|FIX;
         u_int      4   4  ORDER(little)|FIX|UNSGNED;
         double     8   8  ORDER(little)|FLOAT(64,11,52,0,1,12,0,1023);
         REAL       8   8  ORDER(little)|FLOAT(64,11,52,0,1,12,0,1023)|TYPEDEF(double);
         function   4   4  ORDER(little)|FIX;
         Directory  1   0  NO-CONV|FIX;

      StructAlignment: 0
      DefaultIndexOffset: 0
      MajorOrder: row
B) CompoundTypes

Compound types are constructed from primitive types and other compound types. This section begins with a line containing just the tag, "CompoundTypes:". Each compound type begins with a line of the form:


      <type> (<Nbytes>)
where
      <type>   := the name of the compound type
      <Nbytes> := the number of bytes required to represent one
                  instance of <type> on disk
The members of the compound type are specified one per line. The syntax is:
       {<member>
        <member>
           .
           .
           .
        <member>};
where
      <member> := <type> <name> [<- <cast>];
      <type>   := the name of the type of the member
      <name>   := the name of the member
      <cast>   := the name of the member whose true type
                  this member contains (this member must
                  have <type> "char *")
The following example illustrates:
      CompoundTypes:
         pcons (16)
            {char *car_type;
             char *car <- car_type;
             char *cdr_type;
             char *cdr <- cdr_type;};
C) SymbolTable

The symbol table associates a name with the information describing an object written to the file. This section begins with a line containing just the tag, "SymbolTable:". Each entry is described in a single line of the form:

     <type> <name>[<dimensions>] @ <address> (<Nitems>);
where
     <type>       := is the name of the type of the data
     <name>       := is the name of the entry
                     all names are fit into a hierarchy on the
                     model of a file system and as such begin
                     with '/'
     <dimensions> := <dim_start><dimension>[,<dimension>]*<dim_end>
     <dim_start>  := '(' | '['
     <dimension>  := <length> | <min>:<max>
     <dim_end>    := ')' | ']'
The following example illustrates some of the syntax:
      SymbolTable:
         Directory / @ 0 (1);
         Directory /&ptrs/ @ 1 (1);
         integer /ia[0:4] @ 41 (5);
         float /fa2[0:3,0:2] @ 61 (12);
         double /da[0:3] @ 109 (4);
         char /ca[0:9] @ 21 (10);
         integer /is @ 5 (1);
         short /sa[0:4] @ 31 (5);
         char * /cap[0:2] @ 141 (3);
         st62 /d71 @ 2 (1);
         double /&ptrs/ia_2 @ 98 (10);
         double /&ptrs/ia_1 @ 10 (10);
D) Extras

Certain metadata does not specifically describe symbol table entries or data types. Also, from time to time extra information is added to PDB files to adapt to new requirements. This information is placed in the extras table. The data in the extras table is optional and PDBLib has default values for each piece of information which permit backwards compatibility to the greatest possible degree.

The extras appear after the symbol table. The syntax of the entries varies according to the needs of the data, but as a rule of thumb the syntax is:

     <key>: <value>
The following example illustrates some of the syntax:
      UseItags: 0
      Version: 19 (Fri Apr 28 14:04:36 2006)
E) Addresses and Trailer

The last three elements of version III syntax are the addresses of the structure chart (beginning with the PrimitiveTypes section), the symbol table, and a tag which identifies the file as being a PDB file using format version III.

The following example illustrates this syntax:

      StructureChartAddress: 40247
      SymbolTableAddress: 41442
      !<<PDB:3>>!
F) Blocks

PDBLib supports notions like PD_append which allow applications to add more data to an entry in the file. In order to do this with the greatest flexibility and economy of disk space, PDBLib allows a variable to be stored in discontiguous blocks of space in the file. Logically, the variable is contiguous, only the underlying storage pattern is discontiguous.

If a variable is completely contiguous, its symbol table entry in the file has a complete specification. If a variable has discontiguous parts, its symbol table entry in the file completely describes the first continguous part (this makes non-PDB readers able to make sense of at least some of the data). The remainder of the variable is described by a list of blocks in the extras section of the file.

By virtue of the fact the PDB only allows extending the most slowly increasing dimension, it is sufficient that a block specify the number of items in the discontiguous piece and its starting address.

A section in the extras part of the file which begins with the tag "Blocks:" contains all of the block information for all variables in the file. Each entry has the form:

       <name> <n-blocks>
           <addr> <n-items>          n-blocks pairs
where
       <name>     := the name of the variable
       <n-blocks> := the number of block specifcations
                     to follow
       <addr>     := the starting address of the data
                     for the block
       <n-items>  := the number of items in the block
G) Checksums

PDBLib supports per variable checksumming. In practice, since checksumming works with PD_append, it is actually per block checksumming (see the above Blocks section).

Because checksumming is independent of having blocks the per variable checksum information has its own extras section and tag, "Checksums:". Each entry has the form:

       <name> <n-blocks> <n-entries>
           <block-n> <block-checksum>        n-entries 
where
       <name>            := the name of the variable
       <n-blocks>        := the number of block specifcations to follow
       <n-entries>       := the number of checksum specifcations to follow
       <block-n>         := the index of the block whose checksum follow
       <block-checksum>  := the checksum for the specified block
The checksums are laid out this way because it is possible to reserve a block of data with PD_defent and not write to it. Consequently, a variable can have blocks with no checksum and entries are made only for blocks possessing a valid checksum at the time the file is closed.

H) Hidden Directories

PDBLib has the notion of a directory (after the file system model used by most operating systems). All variables are entered in the symbol table as a "full path". This means all symbol table entry names begin with '/'.

PDBLib stores some of its metadata using PDBLib API calls such as PD_write. This has several advantages: minimizes special coding for metadata; and exposes some metadata to generic PDB file browsers such as PDBView.

In order to make plain which information is data and which metadata, PDBLib uses a convention that root level directories whose name begins with '&' contain metadata. By default, such directories will not be listed by PDBView which has earned them the nickname "hidden directories".

Current hidden directories are:

      /&ptrs
      /&etc
I) Pointers

With regard to the handling of pointers, earlier versions of PDBLib did not write the actual pointers into the file (and struct members that were pointers were simply copied unconverted to the file). They wrote a simplified version of a symbol table entry called an ITAG, into the file at the start of the pointee's data. This had the bad effect of mingling data and metadata in the file.

Starting with format version III, PDBLib offers a new model which converts pointers to integer indices that are used to make symbol table entries for the pointees which are then entered in the /&ptrs directory. The pointers are therefore not ignored as they were previously. They are simply another kinds of data which has a well defined conversion algorithm, just as floats or integers do.

With this model it is not necessary to read from the disk to ascertain the location, type, and number information which describe the pointees. That resides in the symbol table which is kept in memory. As a result the performance of PDBLib when handling pointers is much improved.

Pointers are assigned an index, more or less, in the order in which they are written. So as the Nth pointer is written to the file, the number N is what the pointer is converted to and the pointee gets an entry in the symbol table /&ptrs/ia_N.

J) Attributes

The metadata supporting PDBLib's attribute handling is written out in the /&etc hidden directory. The pointers in the attribute table are not written in the /&ptrs directory, but in /&etc along with the attribute table itself.

NOTE: It is PDBLib policy that files with all prior format versions will be readable by all subsequent PDBLib versions. Current PDBLib design allows applications to select the format version they wish to use when creating new files (except for version I - current PDBLib cannot create a version I file any longer). We actively test this in our regression test suite.

Terms

A few definitions must be given first to keep the following summary concise. Some of these will be elaborated upon in the next section.

PDBfile: for the purposes of a program this is a collection of all the relevant information about one of these data files (in the actual coding it is a C struct). See the section on Data Structures for more information.

ENTRY: for the purposes of a program this is a collection of all the relevant information about a variable written to a PDB file.

DEFSTR: for the purposes of a program this is a collection of all the relevant information about a data type in a PDB file.

ASCII: a string

VOID: any data type

TRUE: a value of 1 (defined by PDBLib)

FALSE: a value of 0 (defined by PDBLib)

C context

LAST: a pointer to 0 (declared and defined by PDBLib)

FORTRAN context

LAST: the value 0

REAL*8: an eight byte floating point number.

SX context

TRUE: #t or anything that it not #f or nil.

FALSE: #f or nil.

Data Conversion and Compression

PDBLib has a quasi-universal data translation capability. It is called Parametrized Data Conversion (PDC). A set of parameters which characterizes a large set of integer and floating point formats was developed. It describes the byte size and order of integer types. For floating point data it describes the bit location and width of the sign, exponent, and mantissa field as well as the byte size and order of the data. Using this information a single integer conversion routine and a single floating point conversion routine handle all of the data conversions in PDBLib. An advantage of this approach is that there is no increase in the size of the library for each port to a new environment. Furthermore, it will allow future releases to auto-configure themselves to the machines on which they run. Another benefit is that a data representation may be targeted without regard to its implementation. This provides a vehicle for developing data representations, evaluating them, or using them in a highly abstract manner. One drawback of this approach is that it makes assumptions about the representation of data in computers. While the assumptions are general and the result of incorporating data representations outside these assumptions is more work on the library itself, it is philosophically unsatisfying to make any assumptions about how things are to be done or data to be represented. Another drawback is that by being general purpose the conversion routines are slightly slower than specific ones. This is more than made up for in the saving in library size and ease of porting the library.

Alternative data conversion strategies are either hub and spoke (such as Sun's XDR) or specific format to format. The latter suffers from an N2 growth in the number of conversion routines where N is the number of machine/architectures which the library supports. On the other hand, hub and spoke strategies necessitate a conversion on each read or write operation.

PDC prevents the conversion problem from being N2. At worst, the PDC method should grow like N in the number of parameter sets required. In practice, it is even better than that. Most computer systems today are based on a handful of CPU's which are the most constraining factor in binary data formats. For the convenience of the users of PDBLib, several data_standard's and data_alignment's are predefined by the library itself.

A significant advantage to PDC is that a class of data compression algorithms is implicit in the method. By simply describing a format which describes data in the correct range (up to a possible overall offset for each type), PDBLib can do all of the work to store and retrieve the data in a compressed form.

Using the PDBLib API

There is a hierarchy of routines in PDBLib from high to low level. The high level routines form the API while the lower level routines are modularized to perform the actual work. It should be noted that the lower level routines are sufficiently well modularized so as to make it possible to build entirely different API's for PDBLib.

Comments on the C API

The high level PDBLib routines have a strict naming convention. All high level routines begin with `PD_'. Some routines have several related forms. These are referred to as families of functions. For example the PD_write family.

Most routines maintain a thread of control's error message variable. The value of the error message can be retrieved through a call to PD_get_error. The error messages include the name of the routine in which they are made thus eliminating the need for error codes which must be cross referenced with some other document. In this way application programs can check for error conditions themselves and decide in what manner to use the PDBLib error messages instead of having error messages printed by the system routines. An error message variable is maintained per thread for multi-threaded applications. Error messages are not stacked and must be processed by the application before any other PDBLib calls are made in order to avoid potential overwrites. See the descriptions of individual routines for more information about error handling and messages.

Programs written in C must include a header which makes certain declarations and definitions needed to use the library. Much in the same spirit as one includes stdio.h to use printf and others, include pdb.h as follows:

  #include "pdb.h"
The file pdb.h #include's some other files which must either be in your directory space or pointed to in some manner which your compiler can recognize. The auxiliary #include files are schash.c, scstd.h, and score.h. These files are a part of the SCORE package which you must have to use PDBLib.

Comments on the FORTRAN API

The high level PDBLib routines have a strict naming convention. All routines in the FORTRAN API begin with `PF'.

Note: many of these functions return integer values. The implicit typing convention in FORTRAN would indicate that they return real values. Application programs must explicitly type these functions as integers.

When an error condition is detected by PDBLib it saves a message in a global C character string. FORTRAN programs can access this error message by invoking function PFGERR. The message contains the name of the function in which the error occurred thus eliminating the need for a cross reference document on error codes. In this way applications programs can check for error conditions themselves and decide in what manner to use the PDBLib error messages instead of having error messages printed by the system routines. Error messages are not stacked and must be processed by the application before any other PDBLib calls are made in order to avoid potential overwrites. See the FORTRAN API section for more information about which routines return error messages.

Opening, Creating, Closing, and Controlling PDB Files

These are the most fundamental operations involving PDBLib. The function PD_open is used to either open an existing file or create a new one. PD_close is used to close a PDB file so that it can be recognized by PDBLib for future operations.

PDBLib allows applications to specify the binary format in which a newly created file will be written. PD_target does this work. It is not necessary to invoke PD_target before creating a new PDB file. In this case the binary format is that appropriate for the host system.

During the run of an application code, PDBLib can complete the information in an open PDB file so that in the event of a code crash, the file will be a valid PDB file. This functionality is provided by PD_flush.


PD_SET_BUFFER_SIZE

C Binding:   int PD_set_buffer_size(int v)
F77 Binding: integer PFSBFS(integer v)
SX Binding:  (set-buffer-size! v)
Python Binding:  XXX - missing

Set the buffer size which PDBLib will use for all PDB files to v.

The arguments to this function are: v, an integer value for the buffer size in bytes.

Return the integer value of the buffer size in bytes.


C Example
       int v;
             .
             .
             .

       PD_set_buffer_size(v);
             .
             .
             .

Fortran Example
       integer pfsbfs
       integer v, sz
             .
             .
             .

       sz = pfsbfs(v)
             .
             .
             .

SX Example
             .
             .
             .

       (set-buffer-size! 4096)
             .
             .
             .

Python Example


PD_TARGET

C Binding:   int PD_target(data_standard *std, data_alignment *align)
F77 Binding: integer PFTRGT(integer is, integer ia)
SX Binding:  (target is ia)
Python Binding:  XXX - missing

Write the next PDB file according to the specified data standard and alignment. PDBLib has a general binary data conversion mechanism called parametrized data conversion (PDC). An integer type is described by one set of parameters and a floating point type is described by another. A general purpose conversion routine takes the description of the input type and a description of the desired output type and does the conversion. In this way, PDBLib avoids an N2 increase in data conversion routines as it ports to new machines. In fact, the number of data standards and alignments grows more slowly than N because many machines share common formats.

An additional advantage to PDC is that by specifying a format involving the minimal number of bits to represent the data for a file, PDBLib can carry out a large class of data compressions.

Available data standards are:

C Fortran Byte Order S/I/L/LL F/D
IEEEA_STD 1 NORMAL_ORDER 2,4,4,8 4,8
IEEEB_STD 2 NORMAL_ORDER 2,2,4,4 4,12
IEEEC_STD 3 NORMAL_ORDER 2,4,4,4 4,12
INTELA_STD 4 REVERSE_ORDER 2,2,4,4 4,8
INTELB_STD 5 REVERSE_ORDER 2,4,4,8 4,8
VAX_STD 6 REVERSE_ORDER 2,4,4,8 4,8
CRAY_STD 7 NORMAL_ORDER 8,8,8,8 8,8
IEEED_STD 8 NORMAL_ORDER 2,4,8,8 4,8
IEEEE_STD 9 REVERSE_ORDER 2,4,8,8 4,8
NOTE: S/I/L/LL - short/int/long/longlong  byte sizes
      F/D      - float/double byte sizes

Available data alignments are:

C Fortran C/P/S/I/L/LL/F/D/Str
M68000_ALIGNMENT 1 1,2,2,2,2,2,2,2,0
SPARC_ALIGNMENT 2 1,4,2,4,4,4,4,8,0
MIPS_ALIGNMENT 3 1,4,2,4,4,8,4,8,0
INTEL_ALIGNMENT 4 1,2,2,2,2,2,2,2,0
DEF_ALIGNMENT 5 1,4,4,4,4,4,4,4,0
CRAY_ALIGNMENT 6 4,8,8,8,8,8,8,8,8
UNICOS_ALIGNMENT 7 4,8,8,8,8,8,8,8,8
RS6000_ALIGNMENT 8 1,4,2,4,4,8,4,4,0
NOTE: C/P/S/I/L/LL/F/D/Str - char/pointer/short/int/long/longlong/float/double/struct

In the FORTRAN API, these structures are placed in two arrays and the indices into these arrays are passed into PFTRGT to specify the binary format to be targeted.

Some common configurations are:

Platform C Method Fortran SX Method
Intel 80x86 UNIX PD_target(&INTELB_STD, &INTEL_ALIGNMENT) PFTRGT(5, 4) (target 5 4)
SPARC PD_target(&IEEEA_STD, &SPARC_ALIGNMENT) PFTRGT(1, 2) (target 1 2)
MIPS, SGI PD_target(&IEEEA_STD, &MIPS_ALIGNMENT) PFTRGT(1, 3) (target 1 3)
IBM RS6000 PD_target(&IEEEA_STD, &RS6000_ALIGNMENT) PFTRGT(1, 8) (target 1 8)
Mac/Think C PD_target(&IEEEB_STD, &M68000_ALIGNMENT) PFTRGT(2, 1) (target 2 1)
DEC 3100 PD_target(&INTELB_STD, &MIPS_ALIGNMENT) PFTRGT(5, 3) (target 5 3)
UNICOS Cray PD_target(&CRAY_STD, &UNICOS_ALIGNMENT) PFTRGT(7, 7) (target 7 7)
Motorola PD_target(&IEEEA_STD, &M68000_ALIGNMENT) PFTRGT(1, 1) (target 1 1)
DEC Vax PD_target(&VAX_STD, &DEF_ALIGNMENT) PFTRGT(6, 5) (target 6 5)
Mac/MPW PD_target(&IEEEC_STD, &M68000_ALIGNMENT) PFTRGT(3, 1) (target 3 1)
DOS PD_target(&INTELA_STD, &INTEL_ALIGNMENT) PFTRGT(4, 4) (target 4 4)

The arguments to this function are: std, a pointer to a data_standard structure; is, an index corresponding one of the data_standards; align, a pointer to a data_alignment structure; and ia, an index corresponding to one of the data_alignment structures above. See the section on Data Structures.

The return value is TRUE, if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: DATA_STANDARD and DATA_ALIGNMENT .


C Example
 #include "pdb.h"
 
 void test_target(tgt, base, n, fname, datfile)
    char *tgt, *base;
    int n;
    char *fname, *datfile;
    {if (tgt != NULL)
 
 /* for DOS machines */
        {if (strcmp(tgt, "dos") == 0)
            PD_target(&INTEL_STD, &INTEL_ALIGNMENT);
 
 /* for CRAY computers */
         else if (strcmp(tgt, "cray") == 0)
            PD_target(&CRAY_STD, &UNICOS_ALIGNMENT);
 
 /* for DEC VAX machines */
         else if (strcmp(tgt, "vax") == 0)
            PD_target(&VAX_STD, &DEF_ALIGNMENT);
 
 /* for MIPS based machines */
         else if (strcmp(tgt, "mips") == 0)
            PD_target(&IEEEA_STD, &MIPS_ALIGNMENT);
 
 /* for standard M68000 machines */
         else if (strcmp(tgt, "sun3") == 0)
            PD_target(&IEEEA_STD, &M68000_ALIGNMENT);
 
 /* for SPARC machines */
         else if (strcmp(tgt, "sun4") == 0)
            PD_target(&IEEEA_STD, &SPARC_ALIGNMENT);
 
 /* for Macintosh */
         else if (strcmp(tgt, "mac") == 0)
            PD_target(&IEEEB_STD, &M68000_ALIGNMENT);
 
         sprintf(fname, "%s-%s.rs%d", base, tgt, n);
         sprintf(datfile, "%s-%s.db%d", base, tgt, n);}
     else
        {sprintf(fname, "%s-nat.rs%d", base, n);
         sprintf(datfile, "%s-nat.db%d", base, n);};
 
     return;}

Fortran Example
       integer pftrgt
       integer is, ia
             .
             .
             .

 c ... set target architecture (MIPS, SGI)
 c ... IEEEA_STD
       is = 1
 c ... MIPS_ALIGNMENT
       ia = 3
       if (pftrgt(is, ia) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

 ; set target architecture (MIPS, SGI)
 ; IEEEA_STD is 1 and MIPS_ALIGNMENT is 3
     (target 1 3)
             .
             .
             .

PD_OPEN

C Binding:   PDBfile *PD_open(char *filename, char *mode)
F77 Binding: integer PFOPEN(integer nchr, character name, character mode)
SX Binding:  (open-pdbfile name mode)
Python Binding:  pact.pdb.open(name, mode='r')

Open an existing PDB file or create a new PDB file. Depending on the value of the mode argument, PDBLib attempts to open the file filename in read-only binary mode, open the file in append binary mode, or create a new file in read-write binary mode. Any string which begins with "r" causes the file to be opened in read-only mode, any string beginning with "a" causes the file to be opened in append mode, and any string beginning with "w" causes a file to be created in read-write mode. Next the beginning of the file is searched for the header which identifies the file as having been generated by PDBLib. The addresses of the structure chart and symbol table are then sought.

The structure chart from the file is read in. The structure chart contains information about data types (e.g. floats), their sizes in bytes and their structures if any. By default there are six primitive data types that PDBLib knows about: short integers, integers, long integers, floating point numbers, double precision floating point numbers, characters, and pointers. The sizes of these types vary from machine to machine, but PDBLib hides this from the user.

The symbol table from the file is read in. The symbol table contains the list of variables in the file, their types as defined in the structure chart, and dimensioning information for arrays. Each read from the file first consults the symbol table to see if the requested variable is present in the PDB file.

Both the structure chart and the symbol table are implemented as hash tables, although their shapes are different. This makes lookups as efficient as possible given an unknown amount of data in the file.

The arguments to PD_open() are:
nchr - the number of characters in filename;
filename - an ASCII string, which is the name of the file to be created or opened;
mode - an ASCII string, which is the mode (either "w" for create/write, "r" for read-only or "a" for append).

In the C binding the function returns a pointer to a PDBfile. In the FORTRAN binding the function returns an integer identifier for the PDBfile opened/created. In the Python binding the funtion returns a PDBfile object. This PDBfile identifies the particular file to PDBLib. As such, if it is overwritten, the file is lost. The number of PDB files which can be open simultaneously is machine or operating system dependent, but each open file has a unique PDBfile associated with it.

If any aspect of the PDB file opening process fails, a NULL pointer is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
           .
           .
           .

    if ((file = PD_open("filename", "r")) == NULL)
       printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfopen
       integer fileid
             .
             .
             .

       fileid = pfopen(8, 'file.pdb', 'r')
       if (fileid .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define file (open-pdbfile "foo.pdb" "w"))
             .
             .
             .

Python Example
    import pact.pdb
             .
             .
             .

    file = pact.pdb.open("foo.pdb" "w")
             .
             .
             .

PD_SET_MAJOR_ORDER

C Binding:   void PD_set_major_order(PDBfile *file, int v)
F77 Binding: integer PFSMJO(integer fileid, integer v)
SX Binding:  (major-order file v)
Python Binding:  XXX - missing

Set the major order for PDB file fileid to v. The major order refers to the order of data in multidimensional arrays. See the discussion of this topic in the section PDBLib and Index Ordering.

Input to this function is: fileid, an integer PDBfile identification number, v, an integer value for the major order.

In the C binding return the value of the major order. In the FORTRAN binding return 1 if successful, 0 otherwise.


C Example
       PDBfile *file;
             .
             .
             .

       PD_set_major_order(file, COLUMN_MAJOR_ORDER);
             .
             .
             .

Fortran Example
       integer pfsmjo
       integer fileid, v
             .
             .
             .

       v = 102
       if (pfsmjo(fileid, v) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (major-order file "column-major-order")
             .
             .
             .

Python Example
             .
             .
             .

    file.major_order = "column-major-order"
             .
             .
             .

PD_SET_FORMAT_VERSION

C Binding:   void PD_set_format_version(int v)
F77 Binding: integer PFSFMV(integer v)
SX Binding:  (format-version v)
Python Binding:  XXX - missing

Set the format version to be used when creating new PDB files to v. See the section PDB File Format for a discussion of the PDB file formats.

Input to this function is: v, an integer value for the format version.

In the C binding return the value of the format version. In the FORTRAN binding return 1 if successful, 0 otherwise.


C Example
             .
             .
             .

       PD_set_format_version(3);
             .
             .
             .

Fortran Example
       integer pfsfmv
       integer v
             .
             .
             .

       v = 3
       if (pfsfmv(v) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (format-version 3)
             .
             .
             .

Python Example
             .
             .
             .

PD_SET_MAX_FILE_SIZE

C Binding:   PD_set_max_file_size(PDBfile *file, int v)
F77 Binding: integer PFSMXS(integer fileid, integer v)
SX Binding:  (set-maximum-file-size! file v)
Python Binding:  XXX - missing

Set the maximum file size for PDB file fileid to v. This is used to allow applications to make families of related PDB files and to control the size of the members of the family.

Input to this function is: fileid, an integer PDBfile identification number. Output from this function is: v, an integer value for the maximum file size.

In the C binding return the new integer value of the maximum file size. In the FORTRAN binding return 1 if successful, 0 otherwise.

See also: PD_family .


C Example
       PDBfile *file
             .
             .
             .

       PD_set_max_file_size(fileid, 2000000);
             .
             .
             .

Fortran Example
       integer pfsmxs
       integer fileid, v, sz
             .
             .
             .

       if (pfsmxs(fileid, sz) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

     (set-maximum-file-size! file 100000000)
             .
             .
             .

Python Example
             .
             .
             .

     file.maximum_size = 100000000
             .
             .
             .

PD_SET_OFFSET

C Binding:   void PD_set_offset(PDBfile *file, int v)
F77 Binding: integer PFSOFF(integer fileid, integer v)
SX Binding:  (default-offset file v)
Python Binding:  XXX - missing

Set the default offset for PDB file fileid to v. The default offset refers to the minimum value of a dimension index. PDBLib allows dimensions to be specfied either in "min:max" form, in which case the minimum value is explicit, or in "max" form, in which case the minimum value or offset is assumed. See the discussion in PDBLib and Index Offsets for more details.

Input to this function is: fileid, an integer PDBfile identification number,

Output from this function is: v, an integer value for the default offset.

In the C binding return the value of the offset. In the FORTRAN binding return 1 if successful, 0 otherwise.


C Example
       PDBfile *file;
             .
             .
             .

       PD_set_offset(file, 1);
             .
             .
             .

Fortran Example
       integer pfsoff
       integer fileid, v, sz
             .
             .
             .

       if (pfsoff(fileid, sz) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (default-offset file 0)
             .
             .
             .

Python Example
             .
             .
             .

    file.default-offset = 0
             .
             .
             .

PD_FAMILY

C Binding:   PDBfile *PD_family(PDBfile *file, int flag)
F77 Binding: integer pffami(integer fileid, integer flag)
SX Binding:  (family-file file flag)
Python Binding:  XXX - missing

This function checks to see whether the specified file has exceeded it size limit as set by PD_set_max_file_size. If it has then a new file is opened and returned. If not the given file pointer is returned. The flag is set to TRUE if you want PD_family to close the file it is given. Otherwise the application is responsible for closing the file.

In order to make a family of files the file name is constrained to follow a form that clearly identifies the sequence of files in the family. The name of the file in the original PD_open must be of the form:

          base.[a-zA-Z]dd
where
          d = [0-9a-zA-Z]
This is a 3 digit base 36 integer and permits upto 46656 files in a family.

The arguments to this function are: file, the pointer to the PDBfile structure returned by a previous call to PD_open; fileid, an integer file identifier returned by a previous call to PFOPEN; and flag, an integer value (either TRUE or FALSE).

In the C binding this function returns a pointer to a PDBfile. In the FORTRAN binding this function returns an integer file identifier.

See also: PD_set_max_file_size .


C Example
 #include "pdb.h"
 
    PDBfile *old, *new;
            .
            .

     PD_set_max_file_size(old, 10000000);
            .
            .
            .

     new = PD_family(old, FALSE);
     if (new != old)
        {PD_close(old);
              .
              .
              .

         old = new;};
            .
            .
            .

Fortran Example
    integer old, new
    integer pffami
            .
            .
            .

     new = pffami(old, 0)
     if (new .ne. old) then
        pfclos(old)
              .
              .
              .

        old = new
     endif
            .
            .
            .

SX Example
            .
            .
            .

     (set! old (family-file old #t))
            .
            .
            .

PD_FIX_DENORM

C Binding:  int PD_fix_denorm(data_standard* std, char *type, long len, void *vr)
F77 Binding: integer PFDNRM(integer istd, integer nc, character type,
                 integer len, void vr)

This function checks to see whether the floating point values pointed to by var are denormalized, and if so, sets all denormalized values to 0.0 (zero).

The arguments to this function are: std, the pointer to a data_standard (if NULL the data standard for the current platform will be used); istd, integer id of the data_standard (if -1 the data standard for the current platform will be used); nc, an integer number of characters in the type string; type, the type of values pointed to by var (either "float" or "double"); len, the number of values pointed to by var; and vr, a pointer to the floating point values.

Available data standards are:

C Fortran Byte Order S/I/L/LL F/D
IEEEA_STD 1 NORMAL_ORDER 2,4,4,8 4,8
IEEEB_STD 2 NORMAL_ORDER 2,2,4,4 4,12
IEEEC_STD 3 NORMAL_ORDER 2,4,4,4 4,12
INTELA_STD 4 REVERSE_ORDER 2,2,4,4 4,8
INTELB_STD 5 REVERSE_ORDER 2,4,4,8 4,8
VAX_STD 6 REVERSE_ORDER 2,4,4,8 4,8
CRAY_STD 7 NORMAL_ORDER 8,8,8,8 8,8
IEEED_STD 8 NORMAL_ORDER 2,4,8,8 4,8
IEEEE_STD 9 REVERSE_ORDER 2,4,8,8 4,8
NOTE: S/I/L/LL - short/int/long/longlong  byte sizes
      F/D      - float/double byte sizes

This function returns 1 on success and 0 on failure.

See also: DATA_STANDARD and DATA_ALIGNMENT .


C Example
 #include "pdb.h"
 
    PDBfile *file;
    float* fvalue;
    double* dvalue;

    fvalue = MAKE_N(float, 3);
    dvalue = MAKE_N(double, 1);
            .
            .
            .

    PD_fix_denorm(file->std, "float", 3, fvalue);
    PD_fix_denorm(NULL, "double", 1, dvalue);
            .
            .
            .


Fortran Example
 #include "pdb.h"
       integer pfdnrm
       integer is
       doubleprecision d(100)
             .
             .
             .

       is = -1
       if (pfdnrm(is, 6, "double", 100, d) .eq. 0)
      &   call errproc
             .
             .
             .


PD_FLUSH

C Binding:   int PD_flush(PDBfile *file)
F77 Binding: integer PFFLSH(integer fileid)
SX Binding:  (flush-pdbfile file)
Python Binding:  file.flush()

This function writes out the information which describes the contents of the PDB file specified. Normally, PD_close calls this routine, but applications that want to protect themselves from system failures or other problems may chose to periodically use this function. After a successful return and until or unless more data is written to the file or space reserved for future writes, the PDB file is valid in the sense that if the application terminates unexpectedly before calling PD_close, the file can be PD_open'd successfully.

NOTE: this call does NOT obviate PD_close!

The argument to this function is: file, the pointer to the PDBfile structure returned by a previous call to PD_open; or fileid, the pointer to the PDBfile structure returned by a previous call to PFOPEN.

This function returns TRUE if successful and FALSE is returned and FORTRAN programs may retrieve an error message by invoking function PFGERR.


C Example
 #include "pdb.h"
 
    PDBfile *file;
            .
            .
            .

     if (PD_flush(file) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfflsh
       integer fileid
             .
             .
             .

       if (pfflsh(fileid) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

     (flush-pdbfile file)
             .
             .
             .

Python Example
             .
             .
             .

     file.flush()
             .
             .
             .

PD_CLOSE

C Binding:   int PD_close(PDBfile *file)
F77 Binding: integer PFCLOS(integer fileid)
SX Binding:  (close-pdbfile file)
Python Binding:  file.close()

Close a PDB file.

After all data is written to the PDB file, the structure chart and symbol table must be written out to the file and their disk addresses recorded in the file header. Without these operations the file cannot be read back in by PDBLib and all data is lost. All open PDB files must be closed with PD_close() before exiting the program.

The arguments to PD_close() are:
file - a pointer to a PDBfile;
fileid - an integer file identifier

The function returns TRUE if the PDB file is correctly written and closed;
otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
            .
            .
            .

     if (PD_close(file) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfclos
       integer fileid
             .
             .
             .

       if (pfclos(fileid) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

     (close-pdbfile file)
             .
             .
             .

Python Example
             .
             .
             .

     file.close()
             .
             .
             .

Writing Data to PDB Files

The following paragraphs describe a sequence of increasingly more elaborate output operations for PDB files. They are all compatible with one another so users can select the ones which match their needs best. The most straightforward operations are first.

There are two forms for the most basic data writing operations. These have to do with how the application wants to handle the dimension specifications. The two functions are PD_write and PD_write_alt.

PDBLib supports the notion of writing data of one type out into a file as another type. More precisely, an integer type of data can be written to a file in the format of any other integer type, and similarly for floating point types. The application must take all responsibility for ensuring the appropriateness of this type of conversion (e.g. underflows and overflows). The functions which support this are PD_write_as and PD_write_as_alt.

PDBLib allows applications to append data to existing entries. This is handy in situations where the total amount of data is not known in advance, but a logical ordering of the data is apparent which matches the order in which data will be written. The functions which do this are the PD_append family of functions.

Finally, PDBLib allows applications to reserve space on disk and then let subsequent writes fill in that space with values. This is handy in instances where an application knows a logical structure for a data set but needs to write it out in smaller pieces and not necessarily in the order implied by its logical structure. The functions which let applications reserve space are PD_defent and PD_defent_alt. Reserved spaces may be written to with any of the PD_write family of commands.


PD_WRITE

C Binding:   int PD_write(PDBfile *file, char *name,
                          char *type, void *var)
F77 Binding: integer PFWRTA(integer fileid, integer nchr, character name,
                            integer ntype, character type, void space)
SX Binding:  (write-pdbdata file (type dimension) data)
                    (write-pdbdata file pdbdata)
Python Binding:  file.write(name, var, [outtype, ind])

Write data to a PDB file.

If an entry already exists in the file, the data overwrites the specified file data; otherwise, before writing data to the PDB file an entry is prepared for the symbol table consisting of the name, the type, the dimension information, the disk address to which the data will be written, and the total number of bytes as computed with the help of the structure chart. After the entry is installed in the symbol table the data from memory is converted (only if the target machine type is different from the current machine type) and then written out to disk starting at the current disk address.

The primitive data types which the PDBLib system knows about by default are: "short", "integer", "long", "float", "double", and "char" for short integer, integer, long integer, floating point or real number, double precision floating point number, and character or single byte respectively. Additional types may be added using PD_defstr().

PDBLib supports arbitrary levels of indirections. This means that all types of pointers (except function pointers) can be traced down to the actual data to which they point and that data will be written out into the PDB file in such a way that the read operations can reconstruct the data as it exists prior to the write operation. There is one crucial restriction. That is that the memory associated with any pointer must have been allocated using a SCORE memory management function or macro. See the memory management section near the beginning of this document.

Rationale: When writing out scalar variables (i.e. non-dimensioned variables - structured variables are scalars unless specifically dimensioned) this function is the most convenient to use since it involves no variable argument list and hence no worries about terminating the list. Another situation, which is more common than expected, in which PD_write() would be preferred is when it is desirable to make entries in a PDB file which do not correspond to any variables in the application program. Since string manipulations might be involved in preparing the name under which to write the data, coding in the dimensional information is not any less efficient.

Dimensions can be given in two ways. If the default offset value for the PDB file can be taken as the minimum value for the range which a dimension index can legally run, the maximum value may be specified alone. Alternatively, the minimum value, maximum value, and stride (separated by colons) may be specified. The stride is optional and defaults to 1. For example:

    PD_write(file, "u[30,1:10]", "float", u);

    pfwrta(pid, 10, 'u(30,1:10)', 5, 'float', u)
The arguments to PD_write() are:
file - a pointer to a PDBfile which designates the PDB file to which to attempt to write;
fileid - an integer identifier which designates the PDB file to which to write;
nchr - an integer number of characters in the name string;
name - an ASCII string containing the name of the variable to install in the symbol table;
ntype - an integer number of characters in the type string;
type - an ASCII string specifying the variable type;
var - a pointer to the data to be written. This pointer must be consistent with the type specified, that is it must be a pointer to data with type type. For example:

   char **s, **t;
   int *u;

   PD_write(file, "s", "char **", &s);

   PD_write(file, "t(3)", "char *", t);

   PD_write(file, "u(30,1:10)", "integer", u);
The dimension information is encoded in the ASCII string name, as if in a FORTRAN dimension statement.

Note: PDBLib can only write part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When writing part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is TRUE if successful;
otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

pdbdata is described in the PDB section of: Python Bindings .

Troubleshooting: Rules and Pointers

See also: PD_write_alt and PD_defent .


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float x[20];
           .
           .
           .

     if (!PD_write(file, "x(20)", "float", x))
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfwrta
       integer fileid
       real x(20)
       common /abc/ a(2), b, c(2,2:4)
       real a, b, c
             .
             .
             .

 c ... write array x
       if (pfwrta(fileid, 5, `x(20)', 5, `float', x) .eq. 0)
      &   call errproc
 
 c ... write entire structure abc (previous defined with pfdefs)
       if (pfwrta(fileid, 3, `abc', 3, `abc', a) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define file (open-pdbfile "foo.pdb" "w"))

; write various kinds of integer variables
    (write-pdbdata file "cn" (type "integer" 10) 1 2 3 4 5 6 7 8 9 10))
    (write-pdbdata file "an" (type "integer *") '(1 2 3 4)))
    (write-pdbdata file "en" (type "integer *" 3) '(-1 -2 -3) '(4 5 6) '(7 8 9)))
    (write-pdbdata file "sn" (type "integer **") '((1 2 3 4 5) (6 7 8 9))))

; create pdbdata objects c, a, s, and e
    (define c (write-pdbdata nil "c" (type "char" 10) "bar"))
    (define a (write-pdbdata nil "a" (type "char *") "foo"))
    (define e (write-pdbdata nil "e" (type "char *" 3) "Foo" () "Bar"))
    (define s (write-pdbdata nil "s" (type "char **") '("Hello" "world")))

; write pdbdata objects c, a, s, and e
    (write-pdbdata file "c" c)
    (write-pdbdata file "a" a)
    (write-pdbdata file "e" e)
    (write-pdbdata file "s" s)
             .
             .
             .

Python Example
    import pact.pdb
             .
             .
             .

    file = pact.pdb.open( "/tmp/foo.pdb", "w" )

# Write various kinds of simple integers directly.
    file.write("prime",  9973, "integer")
    file.write("cn",  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "integer")

# Create pdbdata nested integer objects an, en and sn.
    an = pact.pdb.pdbdata( [1, 2, 3, 4], "integer *" )
    en = pact.pdb.pdbdata( [[-1, -2, -3], [4, 5, 6], [7, 8, 9]], "integer *[3]" )
    sn = pact.pdb.pdbdata( [[1, 2, 3, 4, 5], [6, 7, 8, 9]], "integer **" )

# Write pdbdata nested integer objects an, en and sn.
    file.write( "an", an )
    file.write( "en", en )
    file.write( "sn", sn )

# Create pdbdata nested string objects c, a, s, and e.
    c = pact.pdb.pdbdata( "bar", "char[3]" )
    a = pact.pdb.pdbdata( "foo", "char *" )
    e = pact.pdb.pdbdata( [ "Foo", None, "Bar" ], "char *[3]" )
    s = pact.pdb.pdbdata( [ "Hello", "world" ], "char **" )

# Write pdbdata nested string objects c, a, s, and e.
    file.write("c", c)
    file.write("a", a)
    file.write("e", e)
    file.write("s", s)
             .
             .
             .
    file.close()

PD_WRITE_ALT

C Binding:   int PD_write_alt(PDBfile *file, char *name, char *type,
                              void *var, int nd, long *ind)
F77 Binding: integer PFWRTD(integer fileid,
                            integer nchr, character name,
                            integer ntype, character type,
                            void vr, integer nd, integer ind)
SX Binding:  none
Python Binding:  none

Write data to a PDB file. This is an alternate form to PD_write. If an entry already exists in the file, the data overwrites the specified file data; otherwise, before writing data to the PDB file an entry is prepared for the symbol table consisting of the name, the type, the dimension information, the disk address to which the data will be written, and the total number of bytes as computed with the help of the structure chart. After the entry is installed in the symbol table the data from memory is converted (only if the target machine type is different from the current machine type) and then written out to disk starting at the current disk address.

The primitive data types which the PDBLib system knows about by default are: "short", "integer", "long", "float", "double", and "char" for short integer, integer, long integer, floating point or real number, double precision floating point number, and character or single byte respectively. Additional types may be added using PD_defstr.

PDBLib supports arbitrary levels of indirections. This means that, subject to the restrictions spelled out in the section on rules, pointers (except function pointers) can be traced down to the actual data to which they point and that data will be written out into the PDB file in such a way that the read operations can reconstruct the data as it exists prior to the write operation. There is one crucial restriction. That is that the memory associated with any pointer must have been allocated by a SCORE memory management function or macro. See the Memory Management section near the beginning of this document.

The rationale for this function is that in some situations, it is desirable to be able to specify the dimensions without building them into an ASCII string.

The arguments to PD_write_alt are: file, a pointer to a PDBfile which designates the PDB file to which to attempt to write; fileid, an integer identifier which designates the PDB file to which to write; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable to install in the symbol table; ntype, an integer number of characters in the type string; type, an ASCII string specifying the variable type; var, a pointer to the data to be written; nd, then number of dimensions for the variable; and ind, an array of long integers containing (min, max, stride) triples specifying the ranges and strides of the dimensions. The pointer, var, must be consistent with the type specified, that is it must be a pointer to data with type, type. For example:

   char **s, **t;
   int *u;

   PD_write_alt(file, "s", "char **", &s, ...);

   PD_write_alt(file, "t", "char *", t, ...);

   PD_write_alt(file, "u", "integer", u, ...);
Note: PDBLib can only write part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When writing part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

Troubleshooting: Rules and Pointers


C Example
 #include "pdb.h"
 
     PDBfile *file;
     long ind[6];
     float x[20][5];
           .
           .
           .

     ind[0] = 0L;
     ind[1] = 19L;
     ind[2] = 1L;
     ind[3] = -2L;
     ind[4] = 2L;
     ind[5] = 1L;
     if (!PD_write_alt(file, "x", "float", x, 2, ind))
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfwrtd
       integer fileid, nd, ind(6)
       real c(2,2:4)
             .
             .
             .

 c ... write array c
       nd = 2
       ind(1) = 1
       ind(2) = 2
       ind(3) = 1
       ind(4) = 2
       ind(5) = 4
       ind(6) = 1
       if (pfwrtd(fileid, 1, `c', 5, `float', c, nd, ind) .eq. 0)
      &   call errproc
             .
             .
             .

PD_WRITE_AS

C Binding:   int PD_write_as(PDBfile *file, char *name,
                             char *intype, char *outtype, void *var)
F77 Binding: integer PFWRAS(integer fileid,
                            integer nchr, character name,
                            integer ntypin, character intype,
                            integer ntypout, character outtype, void vr)
SX Binding:  none
SX Python:  none

Write the data pointed to by var under name and with intype in PDB file file as data of outtype.

The rationale for this function is that in some situations, it is desirable to not only convert the formats of data of a specified type, but to convert between types. An example that occurs in practice often enough is converting a 32 bit int to a 32 bit long on a machine which only has a 16 bit int.

Input to PD_write_as is: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file to which to write; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable in the PDB file; ntypin, an integer number of characters in the intype string; intype, an ASCII string containing the type of the variable; ntypout, an integer number of characters in the outtype string; outtype, an ASCII string containing the output type of the variable; and var, a pointer to the location where the data is to be stored in memory.

Note: PDBLib can only write part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When writing part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

PD_write_as returns TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

Troubleshooting: Rules and Pointers

See also: PD_write_as_alt and PD_defent_alt .


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float x[20];
           .
           .
           .
     if (!PD_write_as(file, "x(20)", "float", "double", x))
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfwras
       integer fileid
       real*8 x(20)
             .
             .
             .

 c ... write array x of type double as type float
       if (pfwras(fileid, 5, `x(20)', 6, `double', 
      &                               5, `float', x) .eq. 0)
      &   call errproc
             .
             .
             .

PD_WRITE_AS_ALT

C Binding:   int PD_write_as_alt(PDBfile *file,
                                 char *name, char *intype, char *outtype,
                                 void *var, int nd, long *ind)
F77 Binding: integer PFWRAD(integer fileid,
                            integer nchr, character name,
                            integer ntypin, character intype,
                            integer ntypout, character outtype,
                            void vr, integer nd, integer ind)
SX Binding:  none
Python Binding:  none

Write the data pointed to by var under name and with intype in PDB file file as data of outtype. This is an alternate form of PD_write_as.

The rationale for this function is:
    1) that in some situations, it is desirable to not only convert the formats of data of a specified type, but to convert between types. An example that occurs in practice often enough is converting a 32 bit int to a 32 bit long on a machine which only has a 16 bit int.
    2) that in some situations, it is desirable to be able to specify the dimensions without building them into an ASCII string.

Input to PD_write_as_alt is: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file to which to write; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable in the PDB file; ntypin, an integer number of characters in the intype string; intype, an ASCII string containing the type of the variable; ntypout, an integer number of characters in the outtype string; outtype, an ASCII string containing the output type of the variable; var, a pointer to the location where the data is to be stored in memory; nd, an integer number of dimensions; and ind, an array of long integers specifying the ranges of each dimension (min, max, stride).

Note: PDBLib can only write part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When writing part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

PD_write_as_alt returns TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

Troubleshooting: Rules and Pointers


C Example
 #include "pdb.h"
 
     PDBfile *file;
     long ind[6];
     float x[20][5];
           .
           .
           .

     ind[0] = 0L;
     ind[1] = 19L;
     ind[2] = 1L;
     ind[3] = -2L;
     ind[4] = 2L;
     ind[5] = 1L;
     if (!PD_write_as_alt(file, "x", "float", "double", x, 2, ind))
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfwrad
       integer fileid, nd, ind(6)
       real*8 c(2,2:4)
             .
             .
             .

 c ... write array c of type double as type float
       nd = 2
       ind(1) = 1
       ind(2) = 2
       ind(3) = 1
       ind(4) = 2
       ind(5) = 4
       ind(6) = 1
       if (pfwrad(fileid, 1, `c', 6, `double',
      &                           5, `float', c, nd, ind) .eq. 0)
      &   call errproc
             .
             .
             .

PD_APPEND

C Binding:   int PD_append(PDBfile *file, char *name, void *vr)
F77 Binding: integer pfappa(integer fileid, integer nchr,
                            character name, void vr)
SX Binding:  none
Python Binding:  XXX - none

Append data to an entry in the specified file. The type is taken to be the same as for the original entry. The dimensions of the appended data are specified in name. They must match the original entry except for the most slowly varying one. The specification of the most slowly varying dimension must be one of the following:

   min:max => new dimension is old_min:old_max+(max-min+1)
              if min is the default_offset for the file
or
   min:max => new dimension is old_min:max
              if min is old_max+1

The rationale for this function is that some data sets are of unknown size until they are completely written. PDBLib permits any entry to reside in discontiguous blocks of disk space. The library is responsible for reading and writing data correctly across these blocks.

The shape or dimensional information of the entry is a part of the name string. In this respect PD_append behaves just like PD_write.

Input to this function is: file, a pointer to a PDBfile, fileid, an integer identifier for a PDBfile, nchr, an integer character length for the name argument, name, an ASCII string containing the name of the variable and any dimensional information, and vr, a pointer to the data to be appended.

This function returns TRUE, if successful; otherwise, FALSE and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_append_alt, PD_append_as, PD_append_as_alt, PD_defent, PD_defent_alt, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float *fv;
           .
           .
           .

     if (PD_append(file, "x(20)", fv)) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write.


Fortran Example
       integer pfappa, pfwrta
       integer fileid
       real y(10)
             .
             .
             .

 c ... append to x
       if (pfappa(fileid, 7, `x(1:10)', y) .eq. 0)
      &   call errproc
             .
             .
             .

PD_APPEND_ALT

C Binding:   int PD_append_alt(PDBfile *file, char *name,
                               void *vr, int nd, long *ind)
F77 Binding: integer pfappd(integer fileid,
                            integer nchr, character name,
                            void vr, integer nd, integer ind)
SX Binding:  none
Python Binding:  none

Append data to an entry in the specified file. The type is taken to be the same as for the original entry. The dimensions of the appended data are specified in the ind array. They must match the original entry except for the most slowly varying one. The specification of the most slowly varying dimension must be one of the following:

   min:max => new dimension is old_min:old_max+(max-min+1)
              if min is the default_offset for the file
or
   min:max => new dimension is old_min:max
              if min is old_max+1
The rationale for this function is that some data sets are of unknown size until they are completely written. PDBLib permits any entry to reside in discontiguous blocks of disk space. The library is responsible for reading and writing data correctly across these blocks.

The shape or dimensional information of the entry is specified in nd and ind. In this respect PD_append_alt behaves just like PD_write_alt.

Input to this function is: file, a pointer to a PDBfile; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable; vr, a pointer to the data to be appended; nd, an integer number of dimensions; and ind, an array of longs with triples (start, stop, step) defining dimension information.

This function returns TRUE, if successful; otherwise, FALSE and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN programs an error message may be retrieved by invoking the function PFGERR.

See also: PD_append, PD_append_as, PD_append_as_alt, PD_defent, PD_defent_alt, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float *fv;
     long ind[3]
           .
           .
           .

     ind[0] = 0L;
     ind[1] = 20L;
     ind[2] = 1L;
     if (PD_append_alt(file, "x", fv, 1, ind)) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write_alt.


Fortran Example
      integer pfappd
      integer fileid, ind(3)
      real y(20)
            .
            .
            .

c ... append to x
      ind(1) = 1
      ind(2) = 20
      ind(3) = 1
      if (pfappd(fileid, 1, `x', y, 1, ind) .eq. 0)
     &   call errproc
            .
            .
            .

PD_APPEND_AS

C Binding:   int PD_append_as(PDBfile *file
                              char *name,
                              char *intype,
                              void *vr)
F77 Binding: integer PFAPAS(integer fileid,
                              integer nchr,
                              character name,
                              integer ntype,
                              character intype,
                              void vr)
SX Binding:  none
Python Binding:  none

Append data to an entry in the specified file. The output type is taken to be the same as for the original entry. The dimensions of the appended data are specified in the name. They must match the original entry except for the most slowly varying one. The specification of the most slowly varying dimension must be one of the following:

   min:max => new dimension is old_min:old_max+(max-min+1)
              if min is the default_offset for the file
or
   min:max => new dimension is old_min:max
              if min is old_max+1
The rationale for this function is that some data sets are of unknown size until they are completely written. PDBLib permits any entry to reside in discontiguous blocks of disk space. The library is responsible for reading and writing data correctly across these blocks.

The shape or dimensional information of the entry is a part of the name string. In this respect PD_append_as behaves just like PD_write_as.

Input to this function is: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file to which to write; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable and any dimensional information; ntype, an integer number of characters in the intype string; intype, an ASCII string specifying the type of the data to which vr points; and vr, a pointer to the data to be appended.

This function returns TRUE, if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN applications an error message can be retrieved by invoking the function PFGERR.

See also: PD_append, PD_append_alt, PD_append_as_alt, PD_defent, PD_defent_alt, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     double *dv;
           .
           .
           .

     if (PD_append_as(file, "x(20)", "double", dv)) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write_as.


Fortran Example
      integer fileid
      real*8 y(10)
      integer pfapas
            .
            .
            .

c ... append to x
      if (pfapas(fileid, 7, `x(1:10)', 6, `double', y) .eq. 0)
     &   call errproc
            .
            .
            .
Compare this with the example of PFWRAS.


PD_APPEND_AS_ALT

C Binding:   int PD_append_as_alt(PDBfile *file char *name,
                                  char *intype, void *vr,
                                  int nd, long *ind)
F77 Binding: integer PFAPAD(integer fileid,
                            integer nchr, character name,
                            integer ntype, character intype,
                            void vr, integer nd, integer ind)
SX Binding:  none
Python Binding:  none

Append data to an entry in the specified file. The output type is taken to be the same as for the original entry. The dimensions of the appended data are specified in the ind array. They must match the original entry except for the most slowly varying one. The specification of the most slowly varying dimension must be one of the following:

   min:max => new dimension is old_min:old_max+(max-min+1)
              if min is the default_offset for the file
or
   min:max => new dimension is old_min:max
              if min is old_max+1
The rationale for this function is that some data sets are of unknown size until they are completely written. PDBLib permits any entry to reside in discontiguous blocks of disk space. The library is responsible for reading and writing data correctly across these blocks.

The shape or dimensional information of the entry is specified in nd and ind. In this respect PD_append_as_alt behaves just like PD_write_alt.

Input to this function is: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDBfile; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable; ntype, an integer number of characters in the intype string; intype, an ASCII string specifying the type of data to which vr points; vr, a pointer to the data to be appended; nd, an integer number of dimensions; and ind, an array of longs with triples (start, stop, step) defining dimension information.

This function returns TRUE, if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN applications an error message can be retrieved by invoking the function PFGERR.

See also: PD_append, PD_append_alt, PD_append_as, PD_defent, PD_defent_alt, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float *fv;
     long ind[3]
           .
           .
           .

     ind[0] = 0L;
     ind[1] = 20L;
     ind[2] = 1L;
     if (PD_append_as_alt(file, "x", "float", fv, 1, ind)) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write_as_alt.


Fortran Example
      character*8 intype
      integer pfapad, pfwrtd
      integer fileid, ntype, nd, ind(3)
      real x(20) 
      real*8 y(10)
            .
            .
            .

c ... append to x
      ind(2) = 10
      if (pfapad(fileid, 1, `x', 6, `double', y, 1, ind) .eq. 0)
     &     call errproc
            .
            .
            .
Compare this with the example of PFWRAD.


Reserving Space for Future Writes

In some applications one knows the size and shape of a variable in advance of having the data to write. PDBLib permits the user to reserve space (including 0 sized space) for a variable and then later write all or parts of it using one or more PD_write calls.

This is different from appending to a variable which PDBLib also supports. See the discussion of the PD_append family of functions.


PD_DEFENT

C Binding:   syment *PD_defent(PDBfile *file,
                               char *name, char *outtype)
F77 Binding: integer PFDEFA(integer fileid,
                            integer nc, char *name,
                            integer nt, char *type)
SX Binding:  none
Python Binding:  none

Define an entry in the symbol table of the PDB file specified by file. This function reserves space on disk but writes no data. The data can be written with later calls to PD_write, PD_write_alt, PD_write_as, or PD_write_as_alt.

The shape or dimensional information of the entry is a part of the name string. In this respect it behaves as PD_write.

The size of the space reserved can be zero. What this means is that a symbol table entry will be setup, but no space on disk will be set aside. In this case the application must use one of the PD_append family of functions instead of one of the PD_write family.

The rationale for this function is to block out space in a PDB file corresponding to some logical layout of a piece of data. The data may not exist at the time the space is reserved or for some reason it may be desirable to write out the data in pieces. In any case if the type and shape of a variable is known at some point, an entry may be made in the PDB file without writing any data. The space may filled with other PDBLib calls at some later time.

Input to this function is: file, a pointer to a PDBfile, fileid, an integer identifier which designates the PDB file in which to define an entry; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable and any dimensional information, and outtype, an ASCII string specifying the type of data in the file.

In the C binding this function returns a symbol table entry (syment) pointer, if successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error. In the FORTRAN binding the return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.

See also: PD_defent_alt, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     syment *ep;
           .
           .
           .

     if ((ep = PD_defent(file, "x(20)", "float")) == NULL)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write.


Fortran Example

       integer pfdefa
       integer fileid
             .
             .
             .

 c ... define and reserve array x
 c ... declaration for x would be: real x(20)
 
       if (pfdefa(fileid, 5, `x(20)', 5, `float') .eq. 0)
      &   call errproc
             .
             .
             .
Compare this with the example of PFWRTA.


PD_DEFENT_ALT

C Binding:   syment *PD_defent_alt(PDBfile *file, char *name,
                                   char *outtype, int nd, long *ind)
F77 Binding: integer PFDEFD(integer fileid,
                            integer nc, char *name,
                            integer nt, char *outtype,
                            integer nd, integer ind)
SX Binding:  none
Python Binding:  none

Define an entry in the symbol table of the PDB file specified by file. This function reserves space on disk but writes no data. The data can be written with later calls to PD_write, PD_write_alt, PD_write_as, or PD_write_as_alt.

This is an alternate form of PD_defent. The difference is that the dimension information is supplied via the nd and ind arguments instead of being a part of the name string. In this respect it behaves as PD_write_alt does.

The size of the space reserved can be zero. What this means is that a symbol table entry will be setup, but no space on disk will be set aside. In this case the application must use one of the PD_append family of functions instead of one of the PD_write family.

The rationale for this function is to block out space in a PDB file corresponding to some logical layout of a piece of data. The data may not exist at the time the space is reserved or for some reason it may be desirable to write out the data in pieces. In any case if the type and shape of a variable is known at some point, an entry may be made in the PDB file without writing any data. The space may filled with other PDBLib calls at some later time.

Input to this function is: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file in which to define an entry; nchr, an integer number of characters in the name string; name, an ASCII string containing the name of the variable only; ntype, an integer number of characters in the outtype string; outtype, an ASCII string specifying the type of data in the file; nd, an integer specifying the number of dimensions; and ind, an array of long integers containing the minimum and maximum values of the index for each dimension pairwise.

In the C binding this function returns a symbol table entry (syment) pointer, if successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error. In the FORTRAN binding the return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.

See also: PD_defent, PD_write, PD_write_alt, PD_write_as, and PD_write_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     syment *ep;
     long ind[4];
           .
           .
           .

     ind[0] = 0L;
     ind[1] = 19L;
     ind[2] = -2L;
     ind[3] = 2L;
     if ((ep = PD_defent_alt(file, "x", "float", 2, ind)) == NULL)
        printf("%s", PD_get_error());
           .
           .
           .
Compare this with the example of PD_write_alt and note the absence of a two dimensional array in this call.


Fortran Example
       integer pfdefd
       integer fileid, nd, ind(4)
             .
             .
             .

 c ... define and reserve array c
 c ... declaration for c would be: real c(2,2:4)
       nd = 2
       ind(1) = 1
       ind(2) = 2
       ind(3) = 2
       ind(4) = 4
       if (pfdefd(fileid, 1, `c', 5, `float', nd, ind) .eq. 0)
      &   call errproc
             .
             .
             .
Compare with the example for PFWRTD.


Reading Data from PDB Files

Since data in a file has a definite size and shape, the reading operations in PDBLib are somewhat simpler than the writing operation. The PD_read family of operations which is the counterpart of the PD_write family does all of the work in reading data from files.


PD_READ

C Binding:   int PD_read(PDBfile *file, char *name, void *var)
F77 Binding: integer PFREAD(integer fileid,
                            integer nchr, character name, void var)
SX Binding:  (read-pdbdata file name)
Python Binding:  file.read(name)

Read all or part of a data entry from an open PDB file.

The symbol table of the given PDB file is searched for the given name and if it is found the information there is used to read the proper number of bytes from the file, do any conversions, and put the result in memory pointed to by var.

The arguments to PD_read are:
file - a pointer to a PDBfile which designates the PDB file from which to attempt the read;
fileid - an integer identifier which designates the PDB file from which to attempt the read;
nchr - an integer number of characters in the name string;
name - an ASCII string containing the specification of data to be read;
var - a pointer to the location where the data is to be placed.

Note: In each PD_read operation, the type of var must be a pointer to the type of the variable name.

Note: PDBLib can only read part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When reading part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is the number of items successfully read.
An ASCII string error message can be retrieved through a call to PD_get_error if 0 items were read.

Troubleshooting: Rules and Pointers

pdbdata is described in the PDB section of: Python Bindings .

See also: PD_read_alt, PD_read_as, and PD_read_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float x[20];
           .
           .
           .
     if (PD_read(file, "x", x) == 0)
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfread
       integer fileid
       real x(20)
       common /abc/ a(2), b, c(2,2:4)
       real a, b, c
       common /jkl/ j, k, l
       integer j, k, l
             .
             .
             .

 c ... read array x
       if (pfread(fileid, 1, 'x', x) .eq. 0)
      &   call errproc
 
 c ... read first element of member c of structure abc
       if (pfread(fileid, 10, 'abc.c(1,2)', c) .eq. 0)
      &   call errproc
 
 c ... read entire structure jkl
       if (pfread(fileid, 3, 'jkl', j) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define file (open-pdbfile "foo.pdb"))
    (define c1 (read-pdbdata file "c"))
    (define a1 (read-pdbdata file "a"))
    (define e1 (read-pdbdata file "e"))
    (define s1 (read-pdbdata file "s"))
             .
             .
             .

Python Example
    import pact.pdb
             .
             .
             .

    file = pact.pdb.open("foo.pdb")
    c1 = file.read("c")
    a1 = file.read("a")
    e1 = file.read("e")
    s1 = file.read("s")
             .
             .
             .

PD_READ_ALT

C Binding:   int PD_read_alt(PDBfile *file, char *name,
                             void *var, long *ind)
F77 Binding: integer PFPTRD(integer fileid,
                            integer nchr, character name,
                            void var, integer ind)
SX Binding:  none
Python Binding:  none

Read all or part of a data entry from an open PDB file. The symbol table of the given PDB file is searched for the given name and if it is found the information there is used to read the proper number of bytes from the file, do any conversions, and put the result in memory pointed to by var.

The arguments to PD_read_alt are: file, a pointer to a PDBfile which designates the PDB file from which to attempt the read; fileid, an integer identifier which designates the PDB file from which to attempt the read; nchr, an integer number of characters in the name string; name, an ASCII string containing the specification of the data to be read; var, a pointer to the location where the data is to be placed; and ind, an array of long integers consisting of three indexes (start, stop, and step) for each dimension of the entry.

Note: In each PD_read_alt operation, the type of var must be a pointer to the type of the variable name.

Note: PDBLib can only read part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When reading part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is the number of items successfully read. An ASCII string error message can be retrieved through a call to PD_get_error if 0 items were read.

Troubleshooting: Rules and Pointers

See also: PD_read, PD_read_as, and PD_read_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     long ind[3];
     float x[20];
           .
           .
           .

     ind[0] = 3;
     ind[1] = 18;
     ind[2] = 2;
     if (PD_read_alt(file, "x", x, ind) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfptrd
       integer fileid, ind(3)
       real xodd(10)
             .
             .
             .

 c ... read the first 10 odd elements of x into array xodd
       ind(1) = 1
       ind(2) = 20
       ind(3) = 2
       if (pfptrd(fileid, 1, 'x', xodd, ind) .eq. 0)
      &   call errproc
             .
             .
             .

PD_READ_AS

C Binding:   int PD_read_as(PDBfile *file,
                            char *name, char *intype, void *var)
F77 Binding: integer PFRDAS(integer fileid,
                            integer nchr, character name,
                            integer ntype, character intype, void var)
SX Binding:  none.
Python Binding:  none, but see example.

Read data from an open PDB file.

The symbol table of the given PDB file is searched for the given name. If the name is found, the information there is used with the type specified by type to read the proper number of bytes from the file, do any conversions, and put the result in memory pointed to by var. If it is not found, a zero is returned and the error message will indicate "MISSING ENTRY". The type specified overrides the type in the symbol table entry as far as deciding on data conversions goes.

This function is generally used to read floats as doubles and so on. However with sufficient care and understanding of both the file data and C data structuring, it can be used to transmute structured data.

The arguments to PD_read_as are:
file - a pointer to a PDBfile which designates the PDB file from which to attempt the read;
fileid - an integer identifier which designates the PDB file from which to attempt the read;
nchr - an integer number of characters in the name string;
name - an ASCII string containing the specification for the data to be read;
ntype - an integer number of characters in the intype string;
intype - an ASCII string containing the type of the data desired;
var - a pointer to the location where the data is to be placed.

Note: In each PD_read_as operation, the type of var must be a pointer to the type specified by type.

Note: PDBLib can only read part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When reading part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is the number of items successfully read.
An ASCII string error message can be retrieved through a call to PD_get_error if 0 items were read.

Troubleshooting: Rules and Pointers

See also: PD_read, PD_read_alt, and PD_read_as_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     float x[20];
           
           .
           .

 /* x is a double in the file */
     if (PD_read_as(file, "x", "float", x) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfrdas
       integer fileid
       real*8  xx(20)
       integer ierror
       character*128 errmsg
             .
             .
             .

 c     Read array x into array xx as type double.
       if (pfrdas(fileid, 1, 'x', 6, 'double', xx) .eq. 0) then
           ierror = pfgerr( 128, errmsg )
           print *, errmsg
           call exit ( -1 )
       endif
             .
             .
             .

Python Example
# There is no Python binding for PD_read_as() 
# but it can be faked by using the Python conversion methods
# int(), long(), float() and complex(). 

    import pact.pdb
             .
             .
             .

    file = pact.pdb.open( "foo.pdb", "r" )

# Read the variables as is.
    int1     = file.read( "int0" )
    long1    = file.read( "long0" )
    float1   = file.read( "float0" )
    double1  = file.read( "double0" )

# Coerce them into floats.
    x_int    = float( int1 )
    x_long   = float( long1 )
    x_float  = float( float1 )
    x_double = float( double1 )
             .
             .
             .

PD_READ_AS_ALT

C Binding:   int PD_read_as_alt(PDBfile *file,
                                char *name, char *type,
                                void *var, long *ind)
F77 Binding: integer PFRDAD(integer fileid,
                            integer nchr, character name,
                            integer ntype, character intype,
                            void var, integer ind)
SX Binding:  none
Python Binding:  none

Read all or part of a data entry from an open PDB file. The symbol table of the given PDB file is searched for the given name and if it is found the information there is used with the type specified by type to read the proper number of bytes from the file, do any conversions, and put the result in memory pointed to by var. The type specified overrides the type in the symbol table entry as far as deciding on data conversions goes.

This function is generally used to read floats as doubles and so on. However with sufficient care and understanding of both the file data and C data structuring, it can be used to transmute structured data.

The arguments to PD_read_as_alt are: file, a pointer to a PDBfile which designates the PDB file from which to attempt the read; fileid, an integer identifier which designates the PDB file from which to attempt the read; nchr, an integer number of characters in the name string; name, an ASCII string containing the specification of the data to be read; type, an ASCII string containing the type of the data desired; var, a pointer to the location where the data is to be placed; and ind, an array of long integers consisting of three indexes (start, stop, and step) for each dimension of the entry.

Note: In each PD_read_as_alt operation, the type of var must be a pointer to the type specified by type.

Note: PDBLib can only read part of an entry if the type of the terminal node is primitive or a structure which contains no indirections and whose descendant members contain no indirections.

Note: When reading part of a variable, especially a structured variable, the path to the desired part must contain one array reference for each level of indirection traversed.

The return value is the number of items successfully read. An ASCII string error message can be retrieved through a call to PD_get_error if 0 items were read.

Troubleshooting: Rules and Pointers

See also: PD_read, PD_read_as, and PD_read_alt.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     long ind[3];
     float x[20];
           .
           .
           .

 /* x is a double in the file */
     ind[0] = 2;
     ind[1] = 10;
     ind[2] = 2;
     if (PD_read_as_alt(file, "x", "float", x, ind) == FALSE)
        printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfrdad
       integer fileid, ind(3)
       real*8 xdd(10)
             .
             .
             .

 c ... read the first 10 elements of float x into array xdd 
 c ... as type double
       ind(1) = 1
       ind(2) = 10
       ind(3) = 1
       if (pfrdad(fileid, 1, 'x', 6, `double', xdd, ind) .eq. 0)
      &   call errproc
             .
             .
             .

Defining New Data Types

To aid application developers in using structured data PDBLib lets applications define new data types in a PDBfile. New data types may either be derived from other existing data types or they may be primitive (integer types, floating point types, or byte sequences). To define derived types applications should use PD_defstr or PD_defstr_alt. To define primitive types use PD_defix, PD_defloat, or PD_defncv.

Since PDBLib supports pointered data types, it is often the case that a pointer in a derived type may point to data of any kind. In C, casts are used to control this behavior. PDBLib permits a member of a struct which is of type "char *" specify the actual type of another pointered member. The function PD_cast is used to set up this behavior.


PD_CAST

C Binding:   int PD_cast(PDBfile *file, char *type,
                         char *memb, char *contr)
F77 Binding: none
SX Binding:  (make-cast file type memb contr)
Python Binding:  XXX - missing

Dynamically change the type of a structure member. PDBLib supports an extended data typing mechanism called a structure. A structure is a set of declarations of members. Each member is in turn a data type known to the system. In some applications, a structure member is used to point to data of a type which is specified by another member. In the C coding a cast is used to obtain a pointer to the desired data type.

PDBLib supports this same practice by allowing the programmer to override the type of a member as given in the structure definition (see PD_defstr) by supplying the name of a member, whose type must be "char *", which will contain an ASCII string specifying the actual type of the data to which the first member points.

The arguments to PD_cast are: file, a pointer to a PDBfile; type, an ASCII string containing the name of the data structure type in the PDB file; memb, an ASCII string containing the name of the member whose type is to be overridden; and contr, an ASCII string containing the name of the member (whose type must be "char *") which will provide the actual type for memb.

The return value is a TRUE if the cast is successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    struct sample
       {char *type;
        int *a;};
          .
          .
          .

     PD_defstr(file, "sample", "char *type", "int *a", LAST);
     PD_cast(file, "sample", "a", "type");
          .
          .
          .

SX Example
          .
          .
          .

    (make-cast file "sample" "char *type" "int *a")
          .
          .
          .

PD_DEFIX

C Binding:   defstr *PD_defix(PDBfile *file, char *name,
                              long bytespitem, int align, int flg)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Define a primitive integral type (fixed point type) in the PDB file specified by file.

Input to PD_defix is: file, a pointer to a PDBfile; name, an ASCII string containing the name of the new data type; bytespitem, the number of bytes required for 1 item of the new type; align, the byte alignment for the type; and flg, a flag indicating whether the byte ordering of the type is normal or reverse ordered.

PDBLib supplies two #define'd constants which define the two ordering schemes used for fixed point types: NORMAL_ORDER and REVERSE_ORDER. NORMAL_ORDER means that the byte ordering from lowest to highest address as occurs on most CPU's. REVERSE_ORDER means that the byte order goes from highest to lowest address as happens with INTEL and other CPU's.

Compare this information with that found in the discussion of data conversion later in this manual.

A pointer to the new type's defstr is returned if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    defstr *ptr;
           .
           .
           .

     ptr = PD_defix(file, "int40", 5, 1, NORMAL_ORDER);
           .
           .
           .

PD_DEFLOAT

C Binding:   defstr *PD_defloat(PDBfile *file, char *name,
                                long bytespitem, int align, int *ordr,
                                long expb, long mantb, long sbs, long sbe,
                                long sbm, long hmb, long bias)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Define a new floating point type to the PDB file specified by file.

Input to PD_defloat is: file, a pointer to a PDBfile; name, an ASCII string containing the name of the variable in the PDB file; bytespitem, the number of bytes required for an item of the new type; align, the byte alignment for this type; ordr, an array of bytespitem integers specifying the byte order; expb, the number of exponent bits; mantb, the number of mantissa bits; sbs, the position of the sign bit; sbe, the starting bit of the exponent; sbm, the starting bit of the mantissa; hmb, the value of the high order mantissa bit; and bias, the bias of the exponent.

Compare this information with that found in the discussion of data conversion later in this manual.

A pointer to the new type's defstr is returned if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
 int ord_int24[] = {1, 3, 2};
 
    PDBfile *file;
    defstr *ptr;
           .
           .
           .

     ptr = PD_defloat(file, "fp24", 3, 1, ord_int24,
                      7L, 16L, 0L, 1L, 8L, 0L, 0x3F)
           .
           .
           .

PD_DEFNCV

C Binding:   defstr *PD_defncv(PDBfile *file, char *name,
                               long bytespitem, int align)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Define a primitive type that will not undergo format conversion from platform to platform in the PDB file specified by file. Certain data types commonly defined in C programs are used as flags or character holders. With such data types the actual bit pattern contains the meaningful information. This information would be lost under a data conversion operation. This function provides users with a means to define primitive types which will not be converted under any circumstances and therefore preserve the meaningful bit patterns which constitute the intended data.

Input to PD_defncv is: file, a pointer to a PDBfile; name, an ASCII string containing the name of the new data type; bytespitem, the number of bytes required for 1 item of the new type; and align, the byte alignment for the type.

Compare this information with that found in the discussion of data conversion later in this manual.

A pointer to the new type's defstr is returned if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    defstr *ptr;
           .
           .
           .
 /* define a type like the FORTRAN character*8 */
     ptr = PD_defncv(file, "char_8", 8, 1);
           .
           .
           .

PD_DEFSTR

C Binding:   defstr *PD_defstr(PDBfile *file,
                               char *name,
                               char *mem1, ..., memn,
                               int *LAST)
F77 Binding: integer PFDEFS(integer fileid,
                            integer nchr,
                            character name,
                            integer ncm1, character mem1,
                                  ...,
                            integer ncmn, character memn,
                            integer LAST)
SX Binding:  (make-defstr name mem1 ... memn)
             (make-defstr* name mem1 ... memn)
Python Binding:  pact.pdb.defstr(name, (mem1, ..., memn), file=vif)
                 file.defstr(name, (mem1, ..., memn))

Define a data structure for a PDB file. As a matter of programming efficiency and clarity it is useful to be able to refer to more complex structural units than the primitive types: short integers, integers, long integers, floating point numbers, double precision floating point numbers, and characters. Arrays do this in a very simple-minded way. Many modern languages support extended types or structures which allow the programmer to group diverse types of data together in a very sophisticated way.

PDBLib supports an extended data typing mechanism called a structure. A structure is a set of declarations of members. Each member is in turn a data type known to the system. Much of the style and usage of structures comes from the C struct. Note: for FORTRAN versions which do not define any kind of pointer (e.g. ANSI FORTRAN 77) structures defined with this function should not contain pointered members. Because of the memory management features upon which PDBLib now depends, even members whose types are pointers are allowed. The only restrictions on member types are that they not be function pointers and that they be expressible without parentheses. Again any member which is a pointer must have its memory allocated by a SCORE memory management function or macro. See the Memory Management section near the beginning of this manual.

PD_defstr defines structures to the PDB system so that they can be read and written as a whole in a single statement. The members of the structure are processed and an entry in the structure chart is made. Then subsequent references to the new structure type are processed using information from the structure chart. The syntax by which members of a structure are specified is like that for C structs. The formal definition is given below ([ ] enclose optional elements). Self-referential structures are allowed providing the reference is through pointers (like C). The actual type name is used in the reference since PDBLib checks that all member types are already known or are the type being defined.

    <;member>         := <;type> [*...*]<;member name>[(<;dimensions>)]
    <;type>           := <;primitive type> | <;derived type>
    <;member name>    := an ASCII string representing the name of the member
    <;primitive type> := short | integer | long | float | double | char
    <;derived type>   := any PD_defstr'd type
    <;dimensions>     := <;integer> |
                        <;integer : integer> |
                        <;integer>, <;dimensions> |
                        <;integer : integer> <;dimensions>

Dimensions can be given in two ways. If the default offset value for the PDB file can be taken as the minimum value for the range which a dimension index can legally run, the maximum value may be specified alone. Alternatively, the minimum value followed by a colon and the maximum value may be specified. For example,

    integer a(30,1:10)

The arguments to PD_defstr are: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file to which to write; nchr, the integer number of characters in the name string; name, an ASCII string containing the name of the data structure type in the PDB file; and memi, a list of ASCII strings each representing the declaration of a member of a structure are defined above. LAST must terminate the list of members.

In the C binding the return value is a pointer to the entry made in the structure chart if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error. In the FORTRAN binding the return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    defstr *ptr;
    struct sample
       {float x[20];
        float y[20];
        int number;};
           .
           .
           .

     ptr = PD_defstr(file, "sample", "float x(20)", "float y(20)",
                           "int number", LAST);
           .
           .
           .

Fortran Example
       parameter(LAST = 0)
       integer pfdefs
       integer fileid
       common /abc/ j, a(2), b, c(2,2:4)
       real a, b, c
       integer j
             .
             .
             .

       if (pfdefs(fileid,
      &           3,  'abc',
      &           9,  'integer j',
      &           10, 'float a(2)',
      &           7,  'float b',
      &           14, 'float c(2,2:4)',
      &           LAST) .eq. 0)
      &     call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (make-defstr* file "abc" (def-member integer i)
                             (def-member char c 10) 
                             (def-member integer *i1)
                             (def-member char *a)
                             (def-member char **s)
                             (def-member float f))
             .
             .
             .

Python Example
             .
             .
             .


    file.make_defstr("abc", ['integer i',
                             'char c(10)',
                             'integer *i1',
                             'char *a',
                             'char **s',
                             'float f])
             .
             .
             .

PD_DEFSTR_ALT

C Binding:   defstr *PD_defstr_alt(PDBfile *file,
                                   char *name,
                                   int nmemb,
                                   char **members)
F77 Binding: integer PFDEFT(integer fileid,
                            integer nchr,
                            character name,
                            integer nmemb,
                            integer nc(2*nm),
                            character *memb)
SX Binding:  none
Python Binding:  none

Define a data structure for a PDB file. As a matter of programming efficiency and clarity it is useful to be able to refer to more complex structural units than the primitive types: short integers, integers, long integers, floating point numbers, double precision floating point numbers, and characters. Arrays do this in a very simple-minded way. Many modern languages support extended types or structures which allow the programmer to group diverse types of data together in a very sophisticated way.

PDBLib supports an extended data typing mechanism called a structure. A structure is a set of declarations of members. Each member is in turn a data type known to the system. Much of the style and usage of structures comes from the C struct. Because of the memory management features upon which PDBLib now depends, even members whose types are pointers are allowed. The only restrictions on member types are that they not be function pointers and that they be expressible without parentheses. Again any member which is a pointer must have its memory allocated by a SCORE memory management function or macro. See the Memory Management section near the beginning of this manual.

PD_defstr defines structures to the PDB system so that they can be read and written as a whole in a single statement. The members of the structure are processed and an entry in the structure chart is made. Then subsequent references to the new structure type are processed using information from the structure chart. The syntax by which members of a structure are specified is like that for C structs. The formal definition is given below ([ ] enclose optional elements). Self-referential structures are allowed providing the reference is through pointers (like C). The actual type name is used in the reference since PDBLib checks that all member types are already known or are the type being defined.

    <;member>         := <;type> [*...*]<;member name>[(<;dimensions>)]
    <;type>           := <;primitive type> | <;derived type>
    <;member name>    := an ASCII string representing the name of the member
    <;primitive type> := short | integer | long | float | double | char
    <;derived type>   := any PD_defstr'd type
    <;dimensions>     := <;integer> |
                        <;integer : integer> |
                        <;integer>, <;dimensions> |
                        <;integer : integer> <;dimensions>

Dimensions can be given in two ways. If the default offset value for the PDB file can be taken as the minimum value for the range which a dimension index can legally run, the maximum value may be specified alone. Alternatively, the minimum value followed by a colon and the maximum value may be specified. For example,

    integer a(30,1:10)

The arguments to PD_defstr are: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file to which to write; nchr, the integer number of characters in the name string; name, an ASCII string containing the name of the data structure type in the PDB file; nmemb, an integer number of strings in the members array; nc, an array of integer pairs specifying the 0 based offset into the memb array and the number of characters for each member; members, an array of ASCII strings each representing the declaration of a member of a structure are defined above; and memb, an array of characters containing the member specifications.

In the C binding the return value is a pointer to the entry made in the structure chart if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error. In the FORTRAN binding the return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    defstr *ptr;
    char **members;
    struct sample
       {float x[20];
        float y[20];
        int number;};
           .
           .
           .

     members = MAKE_N(char *, 3);
     members[0] = SC_strsave("float x[20]");
     members[1] = SC_strsave("float y[20]");
     members[2] = SC_strsave("integer number");
     ptr = PD_defstr_alt(file, "sample", 3, members);
 
     SFREE(members[0]);
     SFREE(members[1]);
     SFREE(members[3]);
     SFREE(members);
           .
           .
           .
Compare with the example for PD_defstr.


Fortran Example
       integer pfdeft
       integer fileid, nc(6)
       character*8 nm(4)
       common /abc/ a(2), b, c(2,2:4)
             .
             .
             .

       nc(1) = 0
       nc(2) = 10
       nc(3) = 10
       nc(4) = 7
       nc(5) = 17
       nc(6) = 14
       nm(1) = `float a('
       nm(2) = `2)float '
       nm(3) = `bfloat c'
       nm(4) = `(2,2:4) '
       if (pfdeft(fileid, 3, `abc', 3, nc, nm) .eq. 0)
      &    call errproc
             .
             .
             .
Compare with the example for PFDEFS.


PD_TYPEDEF

C Binding:   defstr *PD_typedef(PDBfile *file, char *oname, char *tname)
F77 Binding: none
SX Binding:  (make-typedef file oname tname)
Python Binding:  XXX - missing

Define a an alternate name for an existing type. The intended use of this function is to allow users to make their PDB data types match their C types as closely as possible. It does this by mimicking the C typedef mechanism in a limited way. More accurately it provides an aliasing capability. This can be used in conjunction with either PD_defix or PD_defloat to install a definition of a data type in the host chart (PD_defix and PD_defloat define their types to the file chart only).

Input to PD_typedef is: file, a pointer to a PDBfile; oname, an ASCII string containing the name of the original data type; tname, an ASCII string containing the name of the alias.

A pointer to the original type's defstr is returned if the call is successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    defstr *ptr;
           .
           .
           .

 /* define "enum" as an alias for "integer" */
     ptr = PD_typedef(file, "integer", "enum");
           .
           .
           .

SX Example
           .
           .
           .

    (make-typedef file "integer" "enum")
           .
           .
           .

Defining Attributes

PDBLib supports a general mechanism for managing a class of data which is variously referred to as attributes or meta data. In a great many cases, the careful design of data structures obviates the need for this kind of data. Nevertheless, PDBLib supplies four functions to manage attributive data: PD_def_attribute, PD_rem_attribute, PD_get_attribute, PD_set_attribute.


PD_DEF_ATTRIBUTE

C Binding:   int PD_def_attribute(PDBfile *file, char *attr, char *type)
F77 Binding: integer PFDATT(integer fileid,
                            integer na, char *attr,
                            integer nt, char *type)
SX Binding:  (def-attribute file name type)
Python Binding:  XXX - missing

Define an attribute to the given PDB file. The model of an attribute in PDBLib is an entity that has a name and type. The two supported operations on attributes are to create them and to remove them. An entity in a PDB file can be assigned an attribute value simply by making a call which specifies the entity name, the attribute name, and the attribute value (which is determined by the type). The only association between an entry in a PDB file and any attribute is made by the name in the attribute table and the entry in the symbol table. In particular, this mechanism allows the application developer to define and use entities in a PDB file solely in terms of attributes.

The arguments to this function are: file, a pointer to a PDBfile; na, an integer number of characters in the attr string; attr, an ASCII string containing the name of the attribute being defined; nt, an integer number of characters in the type string; and type, an ASCII string containing the name of the data type in the PDB file.

The return value is TRUE, if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error. FORTRAN programs may retrieve an error message by invoking the function PFGERR.

See also: PD_rem_attribute, PD_set_attribute, and PD_get_attribute.


C Example
 #include "pdb.h"
 
    PDBfile *file;
            .
            .
            .

     if (PD_def_attribute(file, "date", "char *") == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfdatt
       integer fileid
             .
             .
             .

       if (pfdatt(fileid, 4, `date', 6, `char *') .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (def-attribute file "date" "char *")
             .
             .
             .

PD_GET_ATTRIBUTE

C Binding:   void *PD_get_attribute(PDBfile *file,
                                    char *vr, char *attr)
F77 Binding: integer PFGVAT(integer fileid,
                            integer nv, char *vr,
                            integer na char *attr,
                            void value)
SX Binding:  (get-attribute-value file vr attr)
Python Binding:  XXX - missing

Return the value of the specified attribute for the named entity.

The model of an attribute in PDBLib is an entity that has a name and type. The two supported operations on attributes are to create them and to remove them. An entity in a PDB file can be assigned an attribute value simply by calling PD_set_attribute. The only association between an entry in a PDB file and any attribute is made by the name in the attribute table and the entry in the symbol table. In particular, this mechanism allows the application developer to define and use entities in a PDB file solely in terms of attributes.

Attribute values are always assigned by reference and PD_get_attribute returns them the same way. The application may have to make a cast on the returned pointer.

The arguments to this function are: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file from which to get the attribute; nv, an integer number of characters in the var string; vr, an ASCII string containing the name of an entity in the PDB file; na, an integer number of characters in the attr string; attr, an ASCII string containing the name of the attribute being sought; and value, into which the attribute value will be copied.

The return value is a pointer to the value of the attribute if one exists; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_def_attribute, PD_rem_attribute, and PD_set_attribute.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    char *dt;
            .
            .
            .

     dt = (char *) PD_get_attribute(file, "foo", "date");
     if (dt == NULL)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfgvat
       integer fileid
       character*8 dt(10)
             .
             .
             .

       if (pfgvat(fileid, 3, `foo', 4, `date', dt) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
            .
            .
            .

    (define dt (get-attribute-value file "foo" "date"))
            .
            .
            .

PD_REM_ATTRIBUTE

C Binding:   int PD_rem_attribute(PDBfile *file, char *attr)
F77 Binding: integer PFRATT(integer fileid, integer na, char *attr)
SX Binding:  (rem-attribute file attr)
Python Binding:  XXX - missing

Remove the specified attribute. Any entities which have a value for this attribute will have it removed by PDBLib.

The model of an attribute in PDBLib is an entity that has a name and type. The two supported operations on attributes are to create them and to remove them. An entity in a PDB file can be assigned an attribute value simply by calling PD_set_attribute. The only association between an entry in a PDB file and any attribute is made by the name in the attribute table and the entry in the symbol table. In particular, this mechanism allows the application developer to define and use entities in a PDB file solely in terms of attributes.

The arguments to this function are: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file from which to remove the attribute; na, an integer number of characters in the attr string; and attr, an ASCII string containing the name of the attribute being removed.

The return value is TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_def_attribute, PD_get_attribute, and PD_set_attribute.


C Example
 #include "pdb.h"
 
    PDBfile *file;
            .
            .
            .

     if (PD_rem_attribute(file, "date") == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfratt
       integer fileid
             .
             .
             .

       if (pfratt(fileid, 4, `date') .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
            .
            .
            .

    (rem-attribute file "date")
            .
            .
            .

PD_SET_ATTRIBUTE

C Binding:   int PD_set_attribute(PDBfile *file,
                                  char *vr, char *attr, void *vl)
F77 Binding: integer PFSVAT(integer fileid,
                            integer nv, char *vr,
                            integer na char *attr, void vl)
SX Binding:  (set-attribute-value! file vr attr vl)
Python Binding:  XXX - missing

Set the value of the specified attribute for the named entity. Attribute values are always assigned by reference.

The model of an attribute in PDBLib is an entity that has a name and type. The two supported operations on attributes are to create them and to remove them. An entity in a PDB file can be assigned an attribute value simply by calling PD_set_attribute. The only association between an entry in a PDB file and any attribute is made by the name in the attribute table and the entry in the symbol table. In particular, this mechanism allows the application developer to define and use entities in a PDB file solely in terms of attributes.

The arguments to this function are: file, a pointer to a PDBfile; fileid, an integer identifier which designates the PDB file in which the attribute is being set; nv, an integer number of characters in the var string; vr, an ASCII string containing the name of an entity in the PDB file; na, an integer number of characters in the attr string; attr, an ASCII string containing the name of the attribute being set; and vl, a pointer to data whose type matches the attribute type.

The return value is TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_def_attribute, PD_rem_attribute, and PD_get_attribute.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    char *dt;
            .
            .
            .

     dt = SC_strsave("Mon March 23, 1921");
     if (PD_set_attribute(file, "foo", "date", dt) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfsvat
       integer scftcs
       integer fileid
       character*80 dt
             .
             .
             .

       scftcs(dt, `Mon March 27, 1921', 18)
       if (pfsvat(fileid, 3, `foo', 4, `date', dt) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

       (set-attribute-value! file "foo" "date" "Mon 3/27/21")
             .
             .
             .

Queries


PD_GET_BUFFER_SIZE

C Binding:   int PD_get_buffer_size
F77 Binding: integer PFGBFS()
SX Binding:  (buffer-size)
Python Binding:  XXX - missing

Get the current buffer size which PDBLib uses for all PDB files and return it.

This function has no arguments.

Return the current buffer size in bytes, if previously set; otherwise, return -1.


C Example
       int sz;
             .
             .
             .

       sz = PD_get_buffer_size;
             .
             .
             .

Fortran Example
       integer pfgbfs
       integer nb
             .
             .
             .

       nb = pfgbfs()
       if (nb .eq. -1)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

       (define sz (buffer-size))
             .
             .
             .

PD_GET_ERROR

C Binding:   char *PD_get_error(void)
F77 Binding: integer PFGERR(integer nchr, character err)
SX Binding:  (pd-error-message)
Python Binding:  XXX - missing

Get the current PDBLib error message. Return the length of the error message in nchr and the actual message in err. The space for err should be 255 characters long.

The arguments to this function are: nchr, the length of the error message; and err, an ASCII string into which the message is copied.

In the C binding this function returns a pointer to the error message. In the FORTRAN binding this function returns 1 if successful, 0 otherwise.


C Example
       char *err;
             .
             .
             .

       err = PD_get_error();
             .
             .
             .

Fortran Example
       integer pfgerr
       integer ierr
       character*128 err
             .
             .
             .

       ierr = pfgerr(128, err)
             .
             .
             .

SX Example
             .
             .
             .

       (define err (pd-error-message))
             .
             .
             .

PD_GET_FILE_LENGTH

C Binding:   off_t PD_get_file_length(PDBfile *file)
F77 Binding: integer PFGFLN(integer fileid,
                            integer len)
SX Binding:  
Python Binding:  XXX - missing

Return the length of the specified PDB file.

The arguments to PFGFLN are: file, PDBfile designating the desired file; len, the integer byte length of the PDB file in question.

In the C binding returns the byte length of the file. In the FORTRAN binding return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


C Example
       PDBfile *file;
       off_t ln;
             .
             .
             .

       ln = PD_get_file_length(file);
             .
             .
             .

Fortran Example
       integer pfgfln
       integer fileid, ln
             .
             .
             .

       if (pfgfln(fileid, ln) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

        none currently
             .
             .
             .

PD_GET_FILE_NAME

C Binding:   char *PD_get_file_name(PDBfile *file)
F77 Binding: integer PFGFNM(integer fileid,
                            integer nchr, character name)
SX Binding:  (file-info file "name")
Python Binding:  file.name

Return the name of the specified PDB file. The nchr argument contains the length of the buffer on input and the length of the file name on output. If the buffer is not long enough, the length of the file name is returned in nchr and a value of 0 is returned.

The arguments to PFGFNM are: file, PDBfile designating the desired file; fileid, an integer identifier which designates the PDB file in question; nchr, on input an integer number of characters in the name string, on output the length of the actual file name string; name, an ASCII string which will contain the file name upon successful completion.

In the C binding returns the name of the file. In the FORTRAN binding return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


C Example
       PDBfile *file;
       char *nm;
             .
             .
             .

       nm = PD_get_file_name(file);
             .
             .
             .

Fortran Example
       integer pfgfnm
       integer fileid, nc
       character*32 name
             .
             .
             .

       nc = len(name)
       if (pfgfnm(fileid, nc, name) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define name (file-info file "name"))
             .
             .
             .

Python Example
             .
             .
             .

    name = file.name
             .
             .
             .

PD_GET_MAJOR_ORDER

C Binding:   int PD_get_major_order(PDBfile *file)
F77 Binding: integer PFGMJO(integer fileid, integer val)
SX Binding:  (file-info file "major-order")
Python Binding:  file.major_order

Get the major order for PDB file fileid to v. The major order refers to the order of data in multidimensional arrays. See the discussion of this topic in the section PDBLib and Index Ordering.

Input to this function is: fileid, an integer PDBfile identification number.

Output from this function is: val, an integer major order.

In the FORTRAN API TRUE is returned if successful and FALSE otherwise.


C Example
       PDBfile *file;
       int mjo;
             .
             .
             .

       mjo = PD_get_major_order(file);
             .
             .
             .

Fortran Example
       integer pfgmjo
       integer mjo, fileid
             .
             .
             .

       mjo = pfgmjo(fileid)
             .
             .
             .

SX Example
             .
             .
             .

    (define mjo (file-info file "major-order"))
             .
             .
             .

PD_GET_MAX_FILE_SIZE

C Binding:   int PD_get_max_file_size(PDBfile *file)
F77 Binding: integer PFGMXS(integer fileid)
SX Binding:  (file-info file "maximum-size")
Python Binding:  XXX - missing

Get the current maximum file size of PDB file fileid in bytes.

The arguments to this function are: fileid, an integer PDBfile identification number.

Return the integer value of the current maximum file size.


C Example
       PDBfile *file;
             .
             .
             .

       sz = PD_get_max_file_size(file);
             .
             .
             .

Fortran Example
       integer pfgmxs
       integer sz, fileid
             .
             .
             .

       sz = pfgmxs(fileid)
             .
             .
             .

SX Example
             .
             .
             .

    (define size (file-info file "maximum-size"))
             .
             .
             .

Python Example
             .
             .
             .

    size = file.maximum_size
             .
             .
             .

PD_GET_MODE

C Binding:   int PD_get_mode(PDBfile *file)
F77 Binding: integer PFGMOD(integer fileid)
SX Binding:  (file-info file "mode")
Python Binding:  file.mode

Get the current mode of PDB file fileid: 2 (append - 'a'), 3 (open - 'r'), 4 (create - 'w').

The arguments to this function are: fileid, an integer PDBfile identification number.

Return the integer value of the current mode.


C Example
       PDBfile *file;
       int md;
             .
             .
             .

       md = PD_get_mode(file);
             .
             .
             .

Fortran Example
       integer pfgmod
       integer md, fileid
             .
             .
             .

       md = pfgmod(fileid)
             .
             .
             .

SX Example
             .
             .
             .

    (define mode (file-info file "mode"))
             .
             .
             .

Python Example
             .
             .
             .

    mode = file.mode
             .
             .
             .

PD_GET_OFFSET

C Binding:   int PD_get_offset(PDBfile *file)
F77 Binding: integer PFGOFF(integer fileid)
SX Binding:  (file-info file "default-offset")
Python Binding:  file.default_offset

Get the current default offset for PDB file fileid. See the discussion in PDBLib and Index Offsets for more details.

The arguments to this function are: fileid, an integer PDBfile identification number.

Return the integer value of the default offset.


C Example
       PDBfile *file;
       int off;
             .
             .
             .

       off = PD_get_offset(file);
             .
             .
             .

Fortran Example
       integer pfgoff
       integer off, fileid
             .
             .
             .

       off = pfgoff(fileid)
             .
             .
             .

SX Example
             .
             .
             .

    (define offs (file-info file "default-offset"))
             .
             .
             .

Python Example
             .
             .
             .

    offs = file.default_offset
             .
             .
             .

PD_query_entry

C Binding:   syment *PD_query_entry(PDBfile *file, char *name, char *fullname)
F77 Binding: none
SX Binding:  (read-syment file name)
Python Binding:  XXX - 

Inquire about variable name in the specified PDB file. This lookup can be done with an absolute path or relative to the current directory (in the specified PDB file).

Input to this function is:
file - a pointer to a PDBfile;
name - an ASCII string containing the path to the variable (absolute or relative to the current directory);
fullname - a character string which will hold the full path to the variable upon output (use NULL if not desired).

Output from this function is:
In the C binding, return a pointer to a syment (a symbol table entry structure) if successful;
otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.
fullname will contain the full path to this variable.


C Example
       PDBfile  *file;                      /* PDB file pointer */
       char     *path;                      /* the name of the variable */
       char     fullpath[MAXLINE];          /* full path to the variable */
       syment   *ep;                        /* symbol table entry pointer */
       long     size;                       /* no. of elements in variable */
       dimdes   *dims;                      /* array of dims; (max,min) pairs */
       char     *type;                      /* variable type in ASCII */
       long     addr;                       /* address of variable */
             .
             .
             .

       path = "abc";
       ep = PD_query_entry(file, path, fullpath);
       if (ep == NULL)
           printf("%s", PD_get_error());
       else
          {printf( "fullpath (output) = %s\n", fullpath );
           size = PD_entry_number(ep);
           dims = PD_entry_dimensions(ep);
           type = PD_entry_type(ep);
           addr = PD_entry_address(ep);}
             .
             .
             .  
       ep = PD_query_entry(file, "./xyz", fullpath);
       ep = PD_query_entry(file, "/top_dir/docs/xyz_doc", NULL);

SX Example
             .
             .
             .

     (define ep (read-syment file "abc"))

; el will contain (type dimensions number address)
     (define el (pdb->list ep))
             .
             .
             .

PD_get_entry_info

C Binding:   int PD_get_entry_info(syment *ep, char **type, long *size,
                                   int *ndims, long **dims)
F77 Binding: integer PFIVAR(integer fileid,
                            integer nchr, character name,
                            integer ntype, character type,
                            integer size, integer ndims, integer dims)
SX Binding:  none
Python Binding:  none

Extract the descriptive information about a variable. In the C binding, a symbol table entry (possibly obtained by PD_query_entry ) is the input. However, in the FORTRAN binding the name is used.

The C binding deals in dynamically allocated spaces which must be freed by a call to PD_free_entry_info.

Input to this function is:
ep - a symbol table entry;
fileid - an integer PDBfile identification number;
nchr - the number of characters in name;
name - an ASCII string containing the name of the variable.

The function returns 1 if successful, 0 otherwise and an ASCII string error message can be retrieved through a call to PD_get_error.

Output from this function is:
ntype - the number of characters in type;
type - an ASCII string containing the type of the variable;
size - the number of elements in the variable;
ndims - the number of dimensions which the variable has;
dims - an array of the dimensions given as (min, max) pairs.


C Example
       PDBfile  *file;
       char     path[MAXLINE];
       syment   *ep;
       char     *type;
       long     ni;
       int      nd;
       long     *dims;
       int      rv;
       int      ii;
             .
             .
             .

       ep = PD_query_entry(file, "abc", path);
       rv = PD_get_entry_info(ep, &type, &ni, &nd, &dims);
       if (!rv)
          printf("%s", PD_get_error());
       else 
          {printf("Variable type:  %s\n", type);
           printf("Number of elements:  %ld\n", ni);
           printf("Number of dimensions:  %d\n", nd);
           for ( ii = 0; ii < nd; ii++ )
               printf("    Dimension:  %ld:%ld\n", dims[2*ii], dims[2*ii+1]);
             .
             .
             .

           PD_free_entry_info(type, dims);}


Fortran Example
       integer pfivar
       integer fileid, sz, al, ind
             .
             .
             .

       if (pfivar(fileid, 3, `abc', 5 `float',
      &           sz, nd, dims) .eq. 0)
      &   call errproc
             .
             .
             .

PD_free_entry_info

C Binding:   void PD_free_entry_info(char *type, long *dims)
F77 Binding:  XXX - missing
SX Binding:  XXX - missing
Python Binding:  XXX - missing

Deallocate the space pointed to by type and dims, previously allocated by a successful call to PD_get_entry_info.

See PD_get_entry_info for examples.


PD_INQUIRE_TYPE

C Binding:   defstr *PD_inquire_type(PDBfile *file, char *type)
              defstr *PD_inquire_host_type(PDBfile *file, char *type)
F77 Binding: integer PFITYP(integer fileid,
                            integer ntype, character type,
                            void size, integer align, integer ind)
SX Binding:  (read-defstr file type)
Python Binding:  XXX - missing

Inquire about type type in the specified PDB file. PD_inquire_type and PFITYP do the lookup in the file chart in order to give information about data in the file rather than the host chart which would give information about the data type in the hardware on which the application is running. Instead PD_inquire_host_type does the lookup in the host chart to give information about the data type in the hardware on which the application is running.

The input for this function is: file, a PDBfile; fileid, an integer PDBfile identification number; ntype, the number of characters in type; type, an ASCII string containing the name of the type.

In the C binding return a pointer to a defstr which contains the description of the data type. In the FORTRAN binding return 1 if successful, 0 otherwise.

In the FORTRAN binding output for this function is: size, the number of bytes necessary to represent the type; align, the alignment of type in bytes; ind, the number of members which are pointers if type is a derived type.


C Example
       PDBfile *file;
       long sz;
       int al, ind;
       memdes *md;
             .
             .
             .

       dp = PD_inquire_type(file, "float");
       if (dp != NULL)
          {sz  = dp->size;
           al  = dp->alignment;
           ind = dp->n_indirects;
           md  = dp->members;};
             .
             .
             .

Fortran Example
       integer pfityp
       integer fileid, sz, al, ind
             .
             .
             .

       if (pfityp(fileid, 5, `float', sz, al, ind) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

     (define dp (read-defstr file "float"))

; dl will contain (type size members)
     (define dl (pdb->list dp))
             .
             .
             .

PFIMBR

C Binding:   none
F77 Binding: integer PFIMBR(integer fileid, integer ntype, char *type,
                            integer n, integer size, char *space)
SX Binding:  none

Inquire about the nth member of the type type in PDB file fileid. Return the description of the member in the character buffer, space. On input size is the number of characters in the buffer space. If the member description requires more space, size is set to the number of bytes required and 0 is returned.

Input to this function is: fileid, an integer PDBfile identification number; ntype, the number of characters in type; type, an ASCII string containing the name of the type; n, an integer specifying the member; size, an integer character size of the space buffer; and space, an character buffer to hold the member description.

Output from this function is: size, the number of characters in the member description; and space, the member description.

The return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.

See also: PD_defstr and PD_defstr_alt .


Fortran Example
       integer pfimbr
       integer fileid
       character*8 type(10), desc(10), bdesc(100)
             .
             .
             .

       size = 80
       if (pfimbr(fileid, 3, `foo', 4, size, desc) .eq. 0) then
          if (size .le. 800) then
             if (pfimbr(fileid, 3, `foo', 4, size, bdesc) .eq. 0) then
      &         call errproc
             endif
          endif
       endif
             .
             .
             .

Using Pointers

The ability to use pointers with PDBLib is very powerful. It is unfortunate perhaps that it can also be a little bit tricky. Application developers should be aware of a key issue when using pointers with PDBLib. In general, when you want to write a data tree, you want to faithfully reproduce the connectivity of the tree. That means that if many pointers refer to the same chunk of memory then the file will exhibit that same pattern. To do this, PDBLib remembers the pointers that it has written and if handed a pointer that it has already written it does NOT write that memory into the file again. It instead makes note of the connection to an already existing region of disk. These same considerations apply to reading with the requisite changes in sense.

The difference between files and memory is that data trees may be created, destroyed, and pointers recycled. For instance, an application may wish to allocate an array, write it as an indirect, change it contents in memory, and write it out again under another name. This is a very common pattern of usage. If PDBLib remembers the pointers, only the first write will put any data on disk. Now PDBLib has no way of knowing what the application wants.

By default PDBLib tracks pointers in order to preserve connectivity patterns in data trees. Applications can exert two kinds of control over the default behavior. First, they can turn of the pointer tracking on a per file basis. Second, they can tell PDBLib to remove or reset its lists of remembered pointers (again on a per file basis).


PD_GET_TRACK_POINTERS

C Binding:   void PD_get_track_pointers(PDBfile *file)
F77 Binding: integer PFGTPT(integer fileid)
SX Binding:  (file-info file "track-pointers")
Python Binding:  XXX - missing

Get the track pointer flag for PDB file fileid. If the track pointer flag is set to FALSE, PDBLib will not record pointers and disk addresses as described above. This obviates the need for calls to PD_reset_ptr_list.

Input to this function is: fileid, an integer PDBfile identification number,

Return the value of the flag.


C Example
       PDBfile *file;
       int fl;
             .
             .
             .

       fl = PD_get_track_pointers(file);
             .
             .
             .

Fortran Example
       integer pfgtpt
       integer fileid, fl
             .
             .
             .

       fl = pfgtpt(fileid)
             .
             .
             .

SX Example
             .
             .
             .

    (define trk (file-info file "track-pointers"))
             .
             .
             .

PD_SET_TRACK_POINTERS

C Binding:   void PD_set_track_pointers(PDBfile *file, int v)
F77 Binding: integer PFSTPT(integer fileid, integer v)
SX Binding:  (set-track-pointers! file v)
Python Binding:  XXX - missing

Set the track pointer flag for PDB file fileid to v. If the track pointer flag is set to FALSE, PDBLib will not record pointers and disk addresses as described above. This obviates the need for calls to PD_reset_ptr_list.

Input to this function is: fileid, an integer PDBfile identification number,

Output from this function is: v, an integer value for the track pointer flag.

In the C binding return the value of the flag. In the FORTRAN binding return 1 if successful, 0 otherwise.


C Example
       PDBfile *file;
             .
             .
             .

       PD_set_track_pointers(file, TRUE);
             .
             .
             .

Fortran Example
       integer pfstpt
       integer fileid
             .
             .
             .

       if (pfstpt(fileid, 1) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (set-track-pointers! file #t)
             .
             .
             .

PD_RESET_PTR_LIST

C Binding:   int PD_reset_ptr_list(PDBfile *file)
F77 Binding: integer PFRSPL(integer fileid)
SX Binding:  (reset-pointer-list! file)
Python Binding:  XXX - missing

Free the list of pointers which the PDB file file knows about. This includes both pointers in memory acquired during write operations and pointers in the file acquired during read operations.

Rationale: When reading or writing indirectly referenced data, PDBLib, maintains an array of pointers encountered in write operations and an array of pointers encountered in read operations. This is done on a per file basis. These arrays are the basis on which PDBLIb can determine how to preserve the connectivity of data trees when they are moved between memory and files. Because of the difference between memory and disk files, it is important for applications to be able to clear out these arrays and start over. See the discussion on Using Pointers earlier in the manual.

The argument to this function is: file a pointer to a PDBfile.

The return value is TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
            .
            .
            .

     if (PD_reset_ptr_list(file) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pfrspl
       integer fileid
             .
             .
             .

       if (pfrspl(fileid) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (reset-pointer-list! file)
             .
             .
             .

PD_FREE

C Binding:   int PD_free(PDBfile *file, char *type, void *var)
F77 Binding: integer PFREE(integer fileid,
                            integer nchr, character type, void var)
SX Binding: 
Python Binding: 

Free memory which was allocated by PDBLib when reading pointers.

Rationale: When reading a variable from a file which has pointers, PDBLib allocates space to hold the actual data. When it comes time to release the memory, the application could walk the data tree which was read by PDBLib for the variable and free any dynamically allocated spaces. PDBLib is also capable of doing this since it understands the structure of the data. Consequently, this function has been included as a convenience for application developers. See the discussion on Using Pointers earlier in the manual.

The argument to this function is: file a pointer to a PDBfile. type the type of the data pointed to by var. var a variable previously read by PDBLib.

The return value is TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    foo vr;
            .
            .
            .

     if (PD_write(file, "bar", "foo", &vr) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

     if (PD_read(file, "bar", &vr) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

     if (PD_free(file, "foo", &vr) == FALSE)
        printf("%s", PD_get_error());
            .
            .
            .

Fortran Example
       integer pffree
       integer fileid
             .
             .
             .

 c ... read array x
       if (pfread(fileid, 3, 'bar', a) .eq. 0)
      &   call errproc
             .
             .
             .

 c ... free array x
       if (pffree(fileid, 3, 'foo', a) .eq. 0)
      &   call errproc
             .
             .
             .

Using Directories


PD_CD

C Binding:   int PD_cd(PDBfile *file, char *dirname)
F77 Binding: integer PFCD(integer fileid,
                          integer nchr, char *dirname)
SX Binding:  (change-directory file dirname)
Python Binding:  file.cd(dirname)

Change the current directory in the specified PDB file.

PDBLib supports an optional hierarchical directory structure inside PDB files. A directory or a variable in a directory may be specified by either a relative path or an absolute path. Slashes separate nodes in a path name. Absolute paths begin with a slash. Nodes consisting of two periods, "..", refer to the next higher level directory.

The arguments to PD_cd are:
file - a pointer to a PDBfile;
fileid - an integer file identifier;
nchr - an integer number of characters in string dirname;
dirname - an ASCII string containing the path name of the directory to change to.

If dirname is NULL or an empty string or a slash, it refers to the top level or root directory.

The return value is TRUE if successful;
otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_ln, PD_ls, PD_mkdir, and PD_pwd.


C Example
 #include "pdb.h"
 
    PDBfile *file;
          .
          .
          .

     if (PD_cd(file, "") == FALSE)
        printf("%s", PD_get_error());
     if (PD_cd(file, "/animals/mammals") == FALSE)
        printf("%s", PD_get_error());
          .
          .
          .

     if (PD_cd(file, "../reptiles") == FALSE)
        printf("%s", PD_get_error());
          .
          .
          .

     if (PD_cd(file, NULL) == FALSE)
        printf("%s", PD_get_error());

Fortran Example
       integer pfcd
       integer fileid
             .
             .
             .

       if (pfcd(fileid, 16, `/animals/mammals') .eq. 0)
      &   call errproc
             .
             .
             .

       if (pfcd(fileid, 11, `../reptiles') .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (change-directory file "/animals/mammals")
             .
             .
             .

Python Example
             .
             .
             .

    file.cd( None )
    file.cd( "/animals/mammals" )
             .
             .
             .

    file.cd( "../reptiles" )
             .
             .
             .

    file.cd( "/" )

PD_LN

C Binding:   int PD_ln(PDBfile *file,
                       char *var, char *link)
F77 Binding: integer PFLN(integer fileid,
                          integer nvar, char *var,
                          integer nlink, char *link)
SX Binding:  (create-link file var link)
Python Binding:  file.ln(var, link)

Create a link to a variable in the specified PDB file.

PDBLib supports an optional hierarchical directory structure inside PDB files. A directory or a variable in a directory may be specified by either a relative path or an absolute path. Slashes separate nodes in a path name. Absolute paths begin with a slash. Nodes consisting of two periods, "..", refer to the next higher level directory.

The arguments to PD_ln are: file, a pointer to a PDBfile; fileid, an integer file identifier; nvar, an integer number of characters in string var; var, an ASCII string containing the path name of an existing variable; nlink, an integer number of characters in string link; and link, an ASCII string containing the path name of the new link.

The return value is a TRUE if successful; otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_cd, PD_ls, PD_mkdir, and PD_pwd.


C Example
 #include "pdb.h"
 
    PDBfile *file;
          .
          .
          .

     if (PD_ln(file, "/animals/mammals/chimpanzee", "/chimp") == FALSE)
        printf("%s", PD_get_error());
          .
          .
          .

Fortran Example
       integer pfln
       integer fileid
             .
             .
             .

       if (pfln(fileid, 27, `/animals/mammals/chimpanzee',
      &                  6, `/chimp') .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (create-link file "/animals/mammals/chimpanzee" "/chimp")
             .
             .
             .

Python Example
             .
             .
             .

    file.ln("/animals/mammals/chimpanzee", "/chimp")
             .
             .
             .

PD_LS

C Binding:   char **PD_ls(PDBfile *file,
                          char *path, char *type, int *num)
F77 Binding: integer PFLST(integer fileid,
                           integer npath, char *path,
                           integer ntype, char *type, integer num)
             integer PFGLS(integer n,
                           integer nchr, char *name)
             integer PFDLS()
SX Binding:  (list-variables file path type)
Python Binding:  file.ls()

Return a list of names of entries (variables and directories) in PDB file file that are of type type and that are in the directory and match the variable name pattern specified by path.

In FORTRAN applications use PFLST to generate an internal table of names of entries (variables and/or directories) in a PDB file that are of a specified type and that are in the directory and match the variable name pattern specified. Then use PFGLS to get the name of the nth entry in the internal table generated by PFLST. Once done with the list use PFDLS to release the internal table.

PDBLib supports an optional hierarchical directory structure inside PDB files. A directory or a variable in a directory may be specified by either a relative path or an absolute path. Slashes separate nodes in a path name. Absolute paths begin with a slash. Nodes consisting of two periods, "..", refer to the next higher level directory.

The arguments to PD_ls are: file, a pointer to a PDBfile; fileid, an integer file identifier; npath, an integer number of characters in string path; path, an ASCII string containing the path name of the directory to search and/or the variable name pattern to match; ntype, an integer number of characters in string type; type, an ASCII string containing the type of entries to return; and num, a pointer to an integer to contain the number of entries returned.

The arguments to PFGLS are: n, an integer ordinal index into the internal table; nchr, an integer to contain the number of characters returned in string name; and name, an ASCII string to contain the returned entry name.

If path is NULL, the contents of the current directory are listed. If type is NULL, all types are returned.

PFGLS copies the name of a symbol table entry into the name, if successful. The application must ensure that name is large enough to contain the longest name in the symbol table (although PDBLib permits names of arbitrary length, 256 characters would probably be more than enough).

The terminal node of path may contain meta characters "*" and "?". Each "*" matches any zero or more characters and each "?" matches any single character.

For the sake of efficiency, the returned names are not duplicated. That is, the caller should not free the space associated with each of the individual strings, but should free the char ** pointer. This should be done using the SFREE macro as shown in the example.

The return value is a pointer to an array of strings, if successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_cd, PD_ln, PD_mkdir, and PD_pwd.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    char **list;
    int num;
          .
          .
          .

 /* get a list of all directories in the current directory */
     list = PD_ls(file, NULL, "Directory", &num);
     if (list == NULL)
        printf("%s", PD_get_error());
          .
          .
          .

     SFREE(list);
          .
          .
          .

 /* get a list of the variables of type char * in directory animals */
     list = PD_ls(file, "animals", "char *", &num);
     if (list == NULL)
        printf("%s", PD_get_error());
          .
          .
          .

     SFREE(list);
          .
          .
          .

Fortran Example
       integer pflst, pfgls, pfdls
       integer fileid
       integer i, nvar, nchr
       character name(256)
             .
             .
             .

 c ... generate a table of all directories in the current directory
       if (pflst(fileid, 0, `', 9, `Directory', nvar) .eq. 0)
      &   call errproc

 c ... get the elements
       do 100 i = 1, nvar
          if (pfgls(i, nchr, name) .eq. 0)
      &      call errproc
             .
             .
             .

   100 continue

 c ... free the table
       if (pfdls() .eq. 0)
      &   call errproc

             .
             .
             .

 c ... generate a table of the variables of type char * in directory animals
       if (pflst(fileid, 7, `animals', 6, `char *', nvar) .eq. 0)
      &     call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define vars (list-variables file "/animals"))
             .
             .
             .

Python Example
             .
             .
             .

    vars = file.ls("/animals")
             .
             .
             .

PFVART

C Binding:   none
F77 Binding: integer PFVART(integer fileid,
                            integer order, integer nvars)
                  integer PFGVAR(integer n, integer nchar, character name)
                  integer PFDVAR()
SX Binding:  none
Python Binding:  none

PFVART generates an internal table of variables in the specified PDB file. With subsequent calls to PFGVAR, each entry can be obtained one at a time by ordinal index. The table is sorted according to a specified scheme. The current choices are alphabetic and by disk address.

PFGVAR gets the name of the nth variable in the internal table generated by a previous call to PFVART. The table will have been sorted in a particular order and this function allows applications to access the variables in the sorted order, not the default hash ordering that would normally apply.

PFGVAR copies the name into the array name, if successful. The application must ensure that name is large enough to contain the longest name in the symbol table (although PDBLib permits names of arbitrary length, 256 characters would probably be more than enough).

Use PFDVAR to release the table created by PFVART.

Rationale: these functions are similar the PD_ls functions. The difference being in the ability to select the ordering criterion. The PD_lst functions sort solely by alphabetical order. It has no counterpart in the C or SX interface because those languages provide other means of accomplishing this capability.

The arguments to PFVART are: fileid, an integer which identifies the PDBfile; order, an integer specifying the sort ordering; and nvars, an integer in which the number of variables in the file is returned.

The choices for order are: 1, for an alphabetic sort; and 2, for a disk address order sort.

The arguments to PFGVAR are: n, an integer ordinal index into the internal sorted name table; nchr, an integer in which the number of characters in the name string is returned; name, an ASCII string which will contain the variable name upon successful completion.

The return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


Fortran Example
       integer pfvart, pfgvar, pfdvar
       integer i, n, nvar, nchar
       character vname(256)
       integer fileid, nvar, order
             .
             .
             .

 c ... create table of variable names in alphabetic order
       order = 1
       if (pfvart(fileid, order, nvar) .eq. 0)
      $   call errproc

 c ... print out the table of variable names created by pfvart
       write(6,700)
  700  format(/,'Alphabetic list of variables:')
       do 701 n = 1, nvar
          if (pfgvar(n, nchar, vname) .eq. 0)
      &        call errproc
          write(6,702) (vname(i), i=1,nchar)
  702     format('            ',256a1)
  701  continue

c ... release the table now
       if (pfdvar() .eq. 0)
      &   call errproc
             .
             .
             .

PD_MKDIR

C Binding:   int PD_mkdir(PDBfile *file, char *dirname)
F77 Binding: integer PFMKDR(integer fileid, integer nchr, char *dirname)
SX Binding:  (make-directory file dirname flag)
Python Binding:  file.mkdir(dirname)

Create a new directory in the specified PDB file.

PDBLib supports an optional hierarchical directory structure inside PDB files. A directory or a variable in a directory may be specified by either a relative path or an absolute path. Slashes separate nodes in a path name. Absolute paths begin with a slash. Nodes consisting of two periods, "..", refer to the next higher level directory.

The arguments to PD_mkdir are:
file - a pointer to a PDBfile;
fileid - an integer file identifier;
nchr - an integer number of characters in string dirname;
dirname - an ASCII string containing the path name of the new directory;
flag - if TRUE report an error if the directory cannot be created.

The root directory, "/", does not have to be created.

The return value is TRUE if successful;
otherwise, FALSE is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_cd, PD_ln, PD_ls, and PD_pwd.


C Example
 #include "pdb.h"
 
    PDBfile *file;
          .
          .
          .

     if (PD_mkdir(file, "/animals/mammals") == FALSE)
        printf("%s", PD_get_error());
          .
          .
          .

Fortran Example
       integer pfmkdr
       integer fileid
             .
             .
             .

       if (pfmkdr(fileid, 16, `/animals/mammals') .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (make-directory file "/animals/mammals")
             .
             .
             .

Python Example
             .
             .
             .

    file.mkdir("/animals/mammals")
             .
             .
             .

PD_PWD

C Binding:   char *PD_pwd(PDBfile *file)
F77 Binding: integer PFPWD(integer fileid, integer nchr, char *dirname)
SX Binding:  (current-directory file)
Python Binding:  file.pwd()

Return the current directory for the specified PDB file.

PDBLib supports an optional hierarchical directory structure inside PDB files. A directory or a variable in a directory may be specified by either a relative path or an absolute path. Slashes separate nodes in a path name. Absolute paths begin with a slash. Nodes consisting of two periods, "..", refer to the next higher level directory.

The arguments to PD_pwd are: file, a pointer to a PDBfile; fileid, an integer file identifier; nchr, an integer to contain the number of characters returned in string dirname; and dirname, an ASCII string to contain the path name of the current directory.

If no directory has been created, "/" is returned. In the FORTRAN binding this function copies the path name of a directory into the dirname, if successful. The application must ensure that dirname is large enough to contain the longest directory name (although PDBLib permits names of arbitrary length, 256 characters would probably be more than enough).

The return value is a pointer to a string containing the path name of the current directory if successful; otherwise, NULL is returned and an ASCII string error message can be retrieved through a call to PD_get_error.

See also: PD_cd, PD_ln, PD_ls, and PD_mkdir.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    char *dirname;
          .
          .
          .

     if ((dirname = PD_pwd(file)) == NULL)
        printf("%s", PD_get_error());
          .
          .
          .

Fortran Example
       integer pfpwd
       integer fileid, nchr
       character dirname(256)
             .
             .
             .

       if (pfpwd(fileid, nchr, dirname) .eq. 0)
      &   call errproc
             .
             .
             .

SX Example
             .
             .
             .

    (define dir (current-directory file))
             .
             .
             .

Python Example
             .
             .
             .

    dir = file.pwd()
             .
             .
             .

Parallel Programming with PDB

PDBLib supports parallel programming on SMP systems using Pthreads or Sprocs and on distributed memory systems using MPI.

Parallel Programming on SMP Systems

When using the thread-safe version of PDBLib the application program must call the library's initialization routine, PD_init_threads, before making any other PDBLib calls. This routine will initialize PDB and SCORE thread specific data structures. With the exception of this one additional initialization call, PDBLib can be used similarly in threaded and serial programs. In multi-threaded applications care must be taken to make sure a file is opened before any read or write calls are issued. Applications must also be careful not to issue PD_close or PD_flush calls while other threads are actively reading or writing.

The thread-safe version of PDBLib can be used by applications to read or write the same file in parallel, or to operate on different files simultaneously. Reading and writing the same file in parallel is, of course, a risky thing to do.

Parallel Programming on Distributed Memory Systems

Applications using this distributed memory library must initialize the library for MPI by calling the routine, PD_init_mpi, before making any other PDBLib calls. This routine will initialize PDB and SCORE for MPI and will initialize the parallel file manager on the specified processor. After all other PDBLib activity is finished, applications must call the termination routine, PD_term_mpi, which will perform library clean-up, including terminating the parallel file manager.

In addition to the special initialization and termination routines, applications performing distributed parallel I/O must use the special MPI versions of the library open and create calls, PD_mp_open and PD_mp_create, in place of PD_open and PD_create when multiple processes will perform I/O to a common file. These routines have an additional argument, an intra-communicator. All participating processes must make the open or create calls, since the MPI-IO functions which provide the low-level I/O define these as collective operations. Each participating process will block on these calls until all processes have made the call. Care must be taken to avoid deadlock when utilizing these collective operations.

Other PDBLib routines that are collective operations include PD_flush, PD_close, and PD_defent. Each of these require that all participating processes make the call before any continue. PDBLib applications that make frequent calls to PD_flush when running in serial mode must examine their flush logic carefully to avoid deadlock when converting to MPI systems. Additionally, PD_flush is an expensive operation in parallel, so should be minimized in any case.

For applications that utilize "distributed arrays", that is, arrays that are decomposed across processes, it is possible to write these to a single array in the PDB file. The PD_defent routine is used to lay out the space in the file that will contain the whole array. The size must be known and specified in the PD_defent call. Subsequent calls to PD_write allow each process to contribute its piece of the distributed array to the file. Remember that since PD_defent is a collective call it must be made by each process and will be a synchronization point in the code.

On systems where threadsafe MPI libraries are available, such as the IBM systems, PDBlib calls to read and/or write can occur asynchronously (i.e. the calls will not block until all processes have made them). On other systems, such as the Compaqs and most others, the lack of threadsafe MPI implementations make it necessary for applications to run in "lock-step", and have all participating processes make the calls before proceeding. This is because on systems with threadsafe MPI PDBlib spawns a thread where the parallel file manager runs. On systems without threadsafe MPI the process designated as the master process in the initialization call will service the parallel file manager requests from other participating processes before returning from PDBlib calls to read or write.


PD_INIT_THREADS

C Binding:   int PD_init_threads(int np, void (*tid)(int *))
F77 Binding: integer PFINTH(integer np, external tid)
SX Binding:  none
Python Binding:  none

Initialize a set of threads for an SMP parallel application. A function, tid, may be supplied to identify the current thread in a parallel execution region. It takes a single integer pointer argument which is used to return a thread index between 0 and np-1. If tid is NULL the built in SCORE function will be used. In this way PDBLib will be able to know which thread it is working on when it is being used in a parallel execution sequence.

PDBLib can be safely used in threaded programs. PD_init_threads should be called before any other PDBLib calls are made so that the thread related PDB and SCORE data structures are properly initialized. Applications which use a thread pool to achieve their parallelism can safely pass a NULL value for the tid argument. The built in SCORE function for returning a thread index is designed to work in such situations. Applications that repeatedly create and destroy threads during the course of a run should provide a function that always sets its argument to a value between 0 and np-1.

The arguments to this function are: np, the number of threads to initialize; and tid, a function which identifies the current thread.

The return value is TRUE if successful; otherwise, FALSE is returned.


C Example
 #include "pdb.h"
 
    int np;
            .
            .
            .

     if (!PD_init_threads(np, NULL))
        printf("Couldn't initialize threads\n");
            .
            .
            .

Fortran Example
       integer pfinth
       integer np
             .
             .
             .

       if (pfinth(np, 0) .eq. 0)
      &   call errproc
             .
             .
             .

PD_INIT_MPI

C Binding:   int PD_init_mpi(int masterproc, int nthreads, void (*tid)(int *))
F77 Binding: integer PFINMP(integer masterproc, integer nthreads, external tid)

Initialize PDBLib for MPI use. The first argument, masterproc, should be the rank of the process that will spawn a control thread. For the current implementation nthreads and tid should be set to 1 and NULL, respectively. Future implementations will allow threads and MPI to coexist in the application.

The call to PD_init_mpi should precede any other PDBLib calls in the application.

The arguments to this function are: masterproc, the rank of the process where the control thread should run; nthreads, the number of threads the application will use (to be implemented, use 1 for now); and tid, a function which identifies the current thread (to be implemented).

The return value is TRUE if successful; otherwise, FALSE is returned.


C Example
 #include "pdb.h"
 
    int masterproc;
    int nthreads = 1;
            .
            .
            .

     if (!PD_init_mpi(masterproc, nthreads, NULL))
        printf("Couldn't initialize PDBLib for MPI\n");
            .
            .
            .

Fortran Example
       integer pfinmp
       integer masterproc, nthreads,
             .
             .
             .

       if (pfinmp(masterproc, nthreads, 0) .eq. 0)
      &   call errproc
             .
             .
             .

PD_TERM_MPI

C Binding:   void PD_term_mpi()
F77 Binding: integer PFTMMP()

Perform any clean-up operations necessary and terminate PDBLib in an MPI application. This call will terminate the PDBLib control thread and perform any other necessary activities when the application is finished using the library. No further PDBLib calls should be made after this call.

The arguments to this function are: none

There is no return value.


C Example
 #include "pdb.h"
 
            .
            .
            .

     PD_term_mpi();
            .
            .
            .

Fortran Example
             .
             .
             .

       call pftmmp()       
             .
             .
             .

PD_MP_OPEN

C Binding:   PDBfile *PD_mp_open(char *filename, char *mode, MPI_Comm comm)
F77 Binding: integer PFMPOP(integer nchr, character name, character mode, integer comm)

Open an existing PDB file in MP parallel mode. With the exception of the additional argument comm, the semantics of this call are identical to those of PD_open. The comm argument should be an MPI communicator which specifies the group of participating processes. The communicator must include the process where the control thread runs in the current implementation. This call is a collective call, therefore every participating process must make the call before any can proceed.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    MPI_Comm comm;
           .
           .
           .

    if ((file = PD_mp_open("filename", "r", comm)) == NULL)
       printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfmpop
       integer fileid
       integer comm
             .
             .
             .

       fileid = pfmpop(8, 'file.pdb', 'r', comm)
       if (fileid .eq. 0)
      &   call errproc
             .
             .
             .

PD_MP_CREATE

C Binding:   PDBfile *PD_mp_create(char *filename, MPI_Comm comm)

Create a PDB file in MP parallel mode. With the exception of the additional argument comm, the semantics of this call are identical to those of PD_create. The comm argument should be an MPI communicator which specifies the group of participating processes. The communicator must include the process where the control thread runs in the current implementation. This call is a collective call, therefore every participating process must make the call before any can proceed.


C Example
 #include "pdb.h"
 
    PDBfile *file;
    SC_communicator comm;
           .
           .
           .

    if ((file = PD_mp_open("filename", "r", comm)) == NULL)
       printf("%s", PD_get_error());
           .
           .
           .

Fortran Example
       integer pfmpop
       integer fileid
       integer comm
             .
             .
             .

       fileid = pfmpop(8, 'file.pdb', 'r', comm)
       if (fileid .eq. 0)
      &   call errproc
             .
             .
             .

Special Purpose I/O

PDBLib is frequently used in connection with visualization of scientific data. To facilitate this four special data structures have special functions dedicated to gathering and writing of this kind of data. The structures are: a curve, a set, a mapping, and an image. The latter three have representations in C structs in various parts of PACT.

If an application produces 1d data sets, writing curves into files would be the general intent. The PACT utility ULTRA can carry out analysis and visualization of such data.

If an application produces multi-dimensional data sets, writing mappings into files would the natural thing to do. Mappings include 1d datasets although they are represented differently than curves. The PACT utility PDBView can do analysis and visualization operations with such data.


PD_PUT_IMAGE

C Binding:   int PD_put_image(PDBfile *file, PD_image *image,
                              int index)
F77 Binding: integer PFWIMA(integer fileid,
                            integer nchr, character name,
                            integer pkn, integer pkx,
                            integer pln, integer plx,
                            real*8 data,
                            real*8 pxn, real*8 pxx,
                            real*8 pyn, real*8 pyx,
                            integer pim)
SX Binding:  none
Python Binding:  none

Build a PD_image structure out of the given input data and write it to a PDB file.

Rationale: The PD_image structure is a useful and general purpose representation of a raster image. The nature of the generalization is that the values in the raster are floating point numbers. So in addition to the standard data sets that can be rasterized, the PD_image can be used to display the computational matrix of some system of equations, for example. This function is a convenient way for FORTRAN programs to put out their data into PDB files as PD_image's for later visualization and processing by other programs. It allows a rectangular subset of a two dimensional array to be specified for the PD_image.

The calling application must keep track of how many PM_image's have been written to each file. PDBLib will write each PM_image under the name composed of the string, `Image', and the integer pim. For example if pim is 9, the PM_image will be written under the name `Image9'. If the application passes the same value for pim more than once only the last one will survive in the symbol table even though the data for each PM_image will persist in the file!

The arguments to PFWIMA are: file, PDBfile for writing; image, PD_image for writing; ind, integer index count; fileid, an integer identifier which designates the PDB file to which to attempt to write; nchr, an integer number of characters in name; name, an ASCII string containing the name of the image; pkn, the integer minimum column index of the data array; pkx, the integer maximum column index of the data array; pln, the integer minimum row index of the data array; plx, the integer maximum row index of the data array; data, an array of real*8 values containing the image data; pxn, a real*8 value specifying the minimum column index in image; pxx, a real*8 value specifying the maximum column index in image; pyn, a real*8 value specifying the minimum row index in image; pyx, a real*8 value specifying the maximum row index in image; and pim, a counter specifying the number of the image being written out.

The return value is 1, if successful; otherwise, 0 is returned and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN programs an error message may be retrieved by invoking function PFGERR.


C Example
       PDBfile *file;
       PD_image *image;
       static int count = 0;
             .
             .
             .

       if (!PD_put_image(file, image, count++))
          printf("%s", PD_get_error());
             .
             .
             .

Fortran Example
       integer pfwima
       integer fileid, k, l
 c ... these arguments to pfwima must have 8 byte element size
       double precision xmin, xmax, ymin, ymax, data(0:10,0:10)
             .
             .
             .

       xmin = 0.0
       xmax = 10.0
       ymin = 0.0
       ymax = 10.0
       do 100 l = 0, 10
          do 101 k = 0, 10
             data(k, l) = (k - 5)**2 + (l - 5)**2
  101     continue
  100  continue
 
       if (pfwima(fileid, 10, 'Test image', 0, 10, 0, 10,
      &           data, xmin, xmax, ymin, ymax, 1) .eq. 0)
      &   call errproc
             .
             .
             .

PD_PUT_MAPPING

C Binding:   int PD_put_mapping(PDBfile *file,
                                PM_mapping *mapping, int index)
F77 Binding: integer PFWMAP(integer fileid,
                            character dname, integer dp, real*8 dm,
                            character rname, integer rp, real*8 rm,
                            integer pim)
SX Binding:  none
Python Binding:  none

Build a PM_mapping structure out of the given input data and write it to a PDB file.

Rationale: The PM_mapping structure is a convenient medium of exchange between data production systems such as simulation codes, storage systems such as PDBLib, and visualization systems such as PDBView. This function is a convenient way for FORTRAN programs to put out their data into PDB files as PM_mapping's for later visualization and processing by other programs.

The PM_mapping is a structure with two main parts: a domain and a range. These two parts are in turn represented by a structure called a PM_set. Because they are both represented as the same type of data object, they are specified similarly in PFWMAP. For each of the domain and range sets the following information is given: a name; an array of integer quantities specifying such information as the dimensionality of the set, the dimensionality of the elements, the number of elements, and so on; and a linear array containing the elements of the set.

The entries in the arrays dp and rp are as follows:

1 the number of characters in the corresponding set name
2 the dimensionality of the set, nd
3 the dimensionality of the set elements, nde
4 the number of elements in the set, ne
5 thru 5+ nd-1 the sizes in each dimension
The layout of the set elements in dm and rm is:

1 thru ne values of the first component
ne+1 thru 2*ne values of the second component
... values of components
(nde-1)*ne+1 thru nde*ne values of the nde'th component
The calling application must keep track of how many PM_mapping's have been written to each file. PDBLib will write each PM_mapping under the name composed of the string, `Mapping', and the integer pim. For example if pim is 9, the PM_mapping will be written under the name `Mapping9'. If the application passes the same value for pim more than once only the last one will survive in the symbol table even though the data for each PM_mapping will persist in the file!

The arguments to PFWMAP are: file, PDBfile for writing; map, PM_mapping to write; ind, PM_mapping index; fileid, an integer identifier which designates the PDB file to which to attempt to write; dname, an ASCII string containing the name of the domain set; dp, an integer array of parameters defining the domain set; dm, an array of real*8 values containing the set elements component by component; rname, an ASCII string containing the name of the range set; rp, an integer array of parameters defining the range set; rm, an array of real*8 values containing the range elements component by component; and pim a counter specifying the number of the mapping being written out.

The return value is 1, if successful; otherwise, 0 is returned and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN programs an error message may be retrieved by invoking function PFGERR.


C Example
       PDBfile *file;
       PM_mapping *f;
       static int count = 0;
             .
             .
             .

       if (!PD_put_mapping(file, f, count++))
          printf("%s", PD_get_error());
             .
             .
             .

Fortran Example
       integer pfwmap
       integer fileid, dp(5), rp(5)
       double precision dm(0:99), rm(0:99)
             .
             .
             .

       dp(1) = 6
       dp(2) = 1
       dp(3) = 1
       dp(4) = 100
       dp(5) = 100
       rp(1) = 6
       rp(2) = 1
       rp(3) = 1
       rp(4) = 100
       rp(5) = 100
 
       do 100 i = 0, 99
          dm(i) = 6.28*float(i)/99.
          rm(i) = sin(6.28*float(i)/99.)
  100  continue
 
       if (pfwmap(fileid, `Domain', dp, dm, `Range', rp, rm, 0)
      &    .eq. 0)
      &   call errproc
             .
             .
             .

PFWRAN

C Binding:   none
F77 Binding: integer PFWRAN(integer fileid,
                            character dname, integer nchr,
                            character rname, integer rp, real*8 rm,
                            integer pim)
SX Binding:  none
Python Binding:  none

Build a PM_mapping structure out of the given input data and write it to a PDB file.

Rationale: The PM_mapping structure is a convenient medium of exchange between data production systems such as simulation codes, storage systems such as PDBLib, and visualization systems such as PDBView. This function is a convenient way for FORTRAN programs to put out their data into PDB files as PM_mapping's for later visualization and processing by other programs.

The PM_mapping is a structure with two main parts: a domain and a range. These two parts are in turn represented by a structure called a PM_set. In many cases a number of PM_mapping's share a common domain set. It is therefore more efficient to write the unique domain sets out separately and use PFWRAN to write out the PM_mapping's without their domains. Post processor codes such as PDBView (by definition) know how to put the full PM_mapping back together. Note: the domain name given for PFWRAN must be the same as the domain name passed to the corresponding PFWSET call.

For each range set the following information is given: a name; an array of integer quantities specifying such information as the dimensionality of the set, the dimensionality of the elements, the number of elements, and so on; and a linear array containing the elements of the set.

The entries in the array rp are as follows:

1 the number of characters in the corresponding set name
2 the dimensionality of the set, nd
3 the dimensionality of the set elements, nde
4 the number of elements in the set, ne
5 thru 5+ nd-1 the sizes in each dimension

The layout of the set elements in rm is:

1 thru ne values of the first component
ne+1 thru 2*ne values of the second component
... values of components
(nde-1)*ne+1 thru nde*ne values of the nde'th component
The calling application must keep track of how many PM_mapping's have been written to each file. PDBLib will write each PM_mapping under the name composed of the string, `Mapping', and the integer pim. For example if pim is 9, the PM_mapping will be written under the name `Mapping9'. If the application passes the same value for pim more than once only the last one will survive in the symbol table even though the data for each PM_mapping will persist in the file.

The arguments to PFWRAN are: fileid, an integer identifier which designates the PDB file to which to attempt to write; dname, an ASCII string containing the name of the domain set; nchr, an integer number of characters in dname; rname, an ASCII string containing the name of the range set; rp, an integer array of parameters defining the range set; rm, an array of real*8 values containing the range elements component by component; and pim a counter specifying the number of the mapping being written out.

The return value is 1, if successful; otherwise, 0 is returned and an error message may be retrieved by invoking function PFGERR.


Fortran Example
       integer pfwran
       integer fileid, i, pim, rp(5)
       double precision rm(0:99)
             .
             .
             .

       pim = 0
       rp(1) = 6
       rp(2) = 1
       rp(3) = 1
       rp(4) = 100
       rp(5) = 100
 
       do 100 i = 0, 99
          rm(i) = sin(6.28*float(i)/99.)
  100  continue
 
 c ... `Domain' written previously by pfwset
       if (pfwran(fileid, `Domain', 6, `Range', rp, rm, pim)
      &    .eq. 0)
      &   call errproc
             .
             .
             .

PD_PUT_SET

C Binding:   int PD_put_set(PDBfile *file, PM_set *set)
F77 Binding: integer PFWSET(integer fileid,
                            character dname, integer dp, real*8 dm)
SX Binding:  none
Python Binding:  none

Build a PM_set structure out of the given input data and write it to a PDB file.

Rationale: The PM_set structure is a fundamental component of the PM_mapping structure which is a convenient medium of exchange between data production systems such as simulation codes, storage systems such as PDBLib, and visualization systems such as PDBView. Although the function PFWMAP most conveniently writes a mapping out to a PDB file, it does not make the best use of limited storage space. In many cases a number of PM_mapping's share a common domain set. It is therefore more efficient to write the unique domain sets out separately and use PFWRAN to write out the PM_mapping's without their domains. Post processor codes such as PDBView (by definition) know how to put the full PM_mapping back together. Note: the domain name given for PFWSET must be the same as the domain name passed to the corresponding PFWRAN call!

For each PM_set the following information is given: a name; an array of integer quantities specifying such information as the dimensionality of the set, the dimensionality of the elements, the number of elements, etc.; and a linear array containing the elements of the set.

The entries in the array dp are as follows:

1 the number of characters in the corresponding set name
2 the dimensionality of the set, nd
3 the dimensionality of the set elements, nde
4 the number of elements in the set, ne
5 thru 5+ nd-1 the sizes in each dimension
The layout of the set elements in dm is:

1 thru ne values of the first component
ne+1 thru 2*ne values of the second component
... values of components
(nde-1)*ne+1 thru nde*ne values of the nde'th component
The arguments to PFWSET are: file, the PDBfile for writing; set, the PM_set to be written; fileid, an integer identifier which designates the PDB file to which to write; dname, an ASCII string containing the name of the PM_set; dp, an integer array of parameters defining the PM_set; and dm, an array of real*8 values containing the set elements component by component.

The return value is 1, if successful; otherwise, 0 is returned and an ASCII string error message can be retrieved through a call to PD_get_error. For FORTRAN programs an error message may be retrieved by invoking function PFGERR.


C Example
       PDBfile *file;
       PM_set *set;
             .
             .
             .

       if (!PD_put_set(file, set))
          printf("%s", PD_get_error());
             .
             .
             .

Fortran Example
       integer pfwset
       integer fileid, i, dp(5)
       double precision dm(0:99)
             .
             .
             .

       dp(1) = 6
       dp(2) = 1
       dp(3) = 1
       dp(4) = 100
       dp(5) = 100
 
       do 100 i = 0, 99
          dm(i) = 6.28*float(i)/99.
  100  continue
 
       if (pfwset(fileid, `Domain', dp, dm) .eq. 0)
      &   call errproc
             .
             .
             .

PD_MAKE_IMAGE

C Binding:   PD_image *PD_make_image(char *name, char *type, void *data,
                                     double dx, double dy, int bpp,
                                     double xmin, double xmax,
                                     double ymin, double ymax,
                                     double zmin, double zmax)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Create and initialize a PD_image data structure.

Input for this function is: name, an ASCII string containing the name of the image; type, an ASCII string containing the data type of the image elements (e.g. "char", "float", "complex"); data, pointer to array of image data of type type; dx, width of image; dy, height of image; bpp, bits per pixel of the image; xmin, minimum value of coordinate associated with image x direction; xmax, maximum value of coordinate associated with image x direction; ymin, minimum value of coordinate associated with image y direction; ymax, maximum value of coordinate associated with image y direction; zmin, minimum value of image data (for palette labeling); and zmax, maximum value of image data (for palette labeling).

Returns a pointer to a PD_image.


C Example
 #include "pdb.h"
 
     PDBfile *file;
     PD_image *im;

     im = PD_make_image();
           .
           .
           .

PD_REL_IMAGE

C Binding:   void PD_rel_image(PD_image *image)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Release the space associated with a PD_image data structure. Input to this function is: image, a pointer to a PD_image.


C Example
 #include "pdb.h"
 
     PD_image *image;
           .
           .
           .

     PD_rel_image(image);
           .
           .
           .

PD_AUTOFIX_DENORM

C Binding:   int PD_autofix_denorm(PDBfile *file, int flag)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Activate automatic zeroing out of denormalized float point primitives during PDB read calls (PD_read, PD_read_as, PD_read_alt, PD_read_as_alt). Does not handle C structures.

Input to this function is: file, a PDB file handle. flag, if flag is TRUE, turn automatic fixing of denormalized floats on for the file; otherwise turn it off.

Returns the old flag value that existed before the function was called.


C Examples

File example:

     #include "pdb.h"
 
     PDBfile *file;
     int old_value;
           .
           .
     /* Turn automatic fixing of denormalized floats on for subsequent read calls */         
     old_value = PD_autofix_denorm(file, TRUE);
           .
           .

PD_ACTIVATE_CKSUM

C Binding:   int PD_activate_cksum(PDBfile *file, int flag)
F77 Binding: integer PFSCSM(integer fileid, int flag)
SX Binding:  (set-activate-checksum! file flag)
Python Binding:  XXX - missing

Activate checksum handling functionality. There are three (3) modes that PDB has available (which can be OR'd together):

If flag is set to PD_MD5_OFF or FALSE, then nothing is enabled and no checksums are calculated or added to the file. If flag is set to PD_MD5_FILE or TRUE on any open, writable file, then an MD5 checksum for the entire file will be placed in the file during any subsequent flush or close operation. If flag is set to PD_MD5_RW on any open, writable file, then any subsequent PD_write will create a hidden MD5 checksum variable associated with the variable being written out and any subsequent PD_read will recalculate and compare MD5 checksums for variables read in (returning -1 and setting PD_error if the checksums do not match). If flag is set to (PD_MD5_FILE | PD_MD5_RW), then both file and variable checksums are handled.

Defaults to PD_MD5_OFF for any file that never had PD_MD5_FILE applied to it. PD_activate_cksum acts like a toggle, hence checksums can be turned off or on for the file (PD_MD5_FILE) and/or for individual variables (PD_MD5_RW) at any time. Note that the MD5 checksum done during PD_write/PD_read calls for variables only currently works for data that contains no pointers. This is because memory addresses in pointers will change from run to run.

Input to this function is: file, a PDB file handle. flag, if flag is PD_MD5_FILE and/or PD_MD5_RW, turn checksum handling on for the file or individual variables, respectively; otherwise turn it off.

Returns the old flag value that existed before the function was called.

See also: PD_verify


C Examples

File example:

     #include "pdb.h"
 
     PDBfile *file;
     int old_value;
           .
           .

/* calculate a checksum for the entire file (only) on PD_flush or PD_close */
     old_value = PD_activate_cksum(file, PD_MD5_FILE);
           .
           .

/* this also calculates a checksum for the entire file and adds it in */      
     PD_close(file);

Variable example:

     #include "pdb.h"
 
     PDBfile *file;
     int old_value, retval;
     float x;
           .
           .

/* turn on both file and variable (read/write) checksums */      
     old_value = PD_activate_cksum(file, PD_MD5_FILE | PD_MD5_RW);
           .
           .

     if (!PD_write(file, "x", "float", &x))
        printf("%s", PD_get_error());
           .
           .

/* read and compares x's checksum with freshly computed one */      
     retval = PD_read(file, "x", &x); 

/* determine if read failed or checksum failed: check error */     
     if ((retval == FALSE) || (retval == -1))
        printf("%s", PD_get_error());         
           .
           .

/* this also calculates a checksum for the entire file and adds it in */      
     PD_close(file);      


PD_VERIFY

C Binding:   int PD_verify(PDBfile *file)
F77 Binding: none
SX Binding:  none
Python Binding:  none

Verifies a file's integrity and determines if the file is corrupt. Uses MD5 checksums.

Input to this function is: file, a PDB file handle.

Returns TRUE if there is an MD5 checksum for the entire file and it matches a freshly computed checksum, returns FALSE if there is an MD5 checksum for the entire file and it does not match a freshly computed checksum, and returns -1 if there is no checksum in the file to verify with.

See also: PD_activate_cksum


C Example
 #include "pdb.h"
 
     PDBfile *file;
     int valid;
           .
           .
           .
     valid = PD_verify(file);

     if (valid == -1)
       printf("PDB file contains no checksum to verify with\n");

     if (!valid)
       printf("PDB file is corrupt\n");
           .
           .
           .

Data Structures in PDBLib

The data structures with which the PDBLib system works are passed back to the application program as the result of the high level calls. This gives the programmer access to a great deal of information about the PDB file, the symbol table and the structure chart. Hopefully, this also makes the package more powerful without pushing any special responsibility onto the programmer.

For application developers who require all of the information from a PDB file, the hash lookup function, SC_def_lookup, can be used to obtain symbol table entries (syment) and structure definitions (defstr) from the symbol table or structure chart. Examples can be found in the section at the end of the manual.

DATA_ALIGNMENT

The set of alignments for the primitive types is kept in a structure called data_alignment. Its actual definition is:

 struct s_data_alignment
    {int char_alignment;
     int ptr_alignment;
     int short_alignment;
     int int_alignment;
     int long_alignment;
     int float_alignment;
     int double_alignment;};
 
 typedef struct s_data_alignment data_alignment;
The term alignment refers to the fact that many CPU's require certain data types to begin at memory locations whose addresses are even multiples of some integer number of bytes. So for example, to say that the alignment of a double is 8 means that a double must begin at an address which is a multiple of 8.

Compilers hide this concept from almost all applications. PDBLib is one that must know data alignments precisely. It employs a structure called a data_alignment to record the alignments of the default primitive data types which PDBLib supports. See the discussion of the data_alignment structure in the section on data structures.

The following is the list of data_alignment's which PDBLib provides automatically (applications can add their own as needed):

SPARC_ALIGNMENT = {1, 4, 2, 4, 4, 4, 8}
MIPS_ALIGNMENT = {1, 4, 2, 4, 4, 4, 8}
RS6000_ALIGNMENT = {1, 4, 2, 4, 4, 4, 4}
CRAY_ALIGNMENT = {8, 8, 8, 8, 8, 8, 8}
UNICOS_ALIGNMENT = {1, 8, 8, 8, 8, 8, 8}
M68000_ALIGNMENT = {1, 2, 2, 2, 2, 2, 2}
INTELA_ALIGNMENT = {1, 2, 2, 2, 2, 2, 2}
INTELB_ALIGNMENT = {4, 4, 4, 4, 4, 4, 4}
INTELC_ALIGNMENT = {2, 4, 2, 4, 4, 4, 4}
DEF_ALIGNMENT = {1, 4, 4, 4, 4, 4, 4}

DATA_STANDARD

The set of information describing all of the primitive data types is organized into a structure called a data_standard. The data_standard characterizes the CPU architecture because all types are either primitive or derived from known types.

Its actual definition is:

 struct s_data_standard
    {int ptr_bytes;
     int short_bytes;
     int short_order;
     int int_bytes;
     int int_order;
     int long_bytes;
     int long_order;
     int float_bytes;
     long *float_format;
     int *float_order;
     int double_bytes;
     long *double_format;
     int *double_order;};
 
 typedef struct s_data_standard data_standard;

Floating Point Format Descriptor

The integer types only require a number of bytes and their order. The floating point types require additional information describing the bit layout of the components of the number: the sign bit; the exponent; and the mantissa. These are given as an array of 8 long integers as follows:

format[0] = # of bits per number
format[1] = # of bits in exponent
format[2] = # of bits in mantissa
format[3] = start bit of sign
format[4] = start bit of exponent
format[5] = start bit of mantissa
format[6] = high order mantissa bit
format[7] = bias of exponent The following floating point format descriptors are defined in PDBLib and used in the data_standard's described in the last section:

ieee_float= {32L, 8L, 23L, 0L, 1L, 9L, 0L, 0x7FL}
ieeea_double= {64L, 11L, 52L, 0L, 1L, 12L, 0L, 0x3FFL}
ieeeb_double= {96L, 15L, 64L, 0L, 1L, 32L, 1L, 0x3FFEL}
intel_float= {32L, 8L, 23L, 0L, 1L, 9L, 0L, 0x7FL}
intel_double= {64L, 11L, 52L, 0L, 1L, 12L, 0L, 0x3FFL}
cray_float= {64L, 15L, 48L, 0L, 1L, 16L, 1L, 0x4000L}

Note: There are several variants of floating type format on the VAX. Accordingly the user must decide which one to use and PDBLib has the descriptions:

When using GFLOATs

vax_float= {32L, 8L, 23L, 0L, 1L, 9L, 0L, 0x81L}
vax_double= {64L, 11L, 52L, 0L, 1L, 12L, 0L, 0x401L}

otherwise

vax_float= {32L, 8L, 23L, 0L, 1L, 9L, 0L, 0x81L}
vax_double= {64L, 8L, 55L, 0L, 1L, 9L, 0L, 0x81L}

Byte Ordering

There is much discussion in the literature about little endian and big endian machines. Those two refer to two possible byte orderings for binary data. That is not the most general way to talk about byte ordering however. In fact the VAX format exemplifies the need for generality. PDBLib simply uses an array of integers which describe the order of the bytes in memory relative to CPU's such as the Motorola and SPARC families.

ieee_float_order= {1, 2, 3, 4}
ieeea_double_order= {1, 2, 3, 4, 5, 6, 7, 8}
ieeeb_double_order= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
intel_float_order= {4, 3, 2, 1}
intel_double_order= {8, 7, 6, 5, 4, 3, 2, 1}
vax_float_order= {2, 1, 4, 3}
vax_double_order= {2, 1, 4, 3, 6, 5, 8, 7}
cray_float_order= {1, 2, 3, 4, 5, 6, 7, 8}

The following is a list of the data_standard's which PDBLib provides by default. The purpose is twofold: to help users identify target formats; and to guide users who wish to create their own data_standard's.

The members of the data_standard are indicated in the template:

STAND
{size of pointer,
size and order of short,
size and order of int,
size and order of long,
size, format, and order of float,
size, format, and order of double}
The various variables indicated are defined by PDBLib.

DEF_STD
{4,
 2, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, def_float, def_float_order,
 8, def_double, def_double_order}

IEEEA_STD
{4,
 2, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, ieee_float, ieee_float_order,
 8, ieeea_double, ieeea_double_order}

IEEEB_STD
{4,
 2, NORMAL_ORDER,
 2, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, ieee_float, ieee_float_order,
12, ieeeb_double, ieeeb_double_order}

IEEEC_STD
{4,
 2, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, NORMAL_ORDER,
 4, ieee_float, ieee_float_order,
12, ieeeb_double, ieeeb_double_order}

INTELA_STD
{4,
 2, REVERSE_ORDER,
 2, REVERSE_ORDER,
 4, REVERSE_ORDER,
 4, intel_float, intel_float_order,
 8, intel_double, intel_double_order}

INTELB_STD
{4,
 2, REVERSE_ORDER,
 4, REVERSE_ORDER,
 4, REVERSE_ORDER,
 4, intel_float, intel_float_order,
 8, intel_double, intel_double_order},

VAX_STD
{4,
 2, REVERSE_ORDER,
 4, REVERSE_ORDER,
 4, REVERSE_ORDER,
 4, vax_float, vax_float_order,
 8, vax_double, vax_double_order}

CRAY_STD
{8,
 8, NORMAL_ORDER,
 8, NORMAL_ORDER,
 8, NORMAL_ORDER,
 8, cray_float, cray_float_order,
 8, cray_float, cray_float_order}

DEFSTR

An entry in the structure chart is represented by a structure called a defstr. It contains information about the data type such as the type name, the byte size and alignment, and a list of members.

DIMDES

A dimdes or dimension descriptor contains the information necessary to characterize a list of dimension specifications. It contains such information as the minimum and maximum values the dimension index may have and the net size of the dimension index range.

MEMDES

A memdes or member descriptor is the structure used to contain the information about a member of a defstr. It contains information about the type of the member, the name of the member, any dimensions which the member may have, and any casts which have been defined via PD_cast.

PDBFILE

The PDBfile is the analog to the FILE structure in standard C I/O. In fact, the PDBfile contains a FILE pointer to access the file via the standard C library functions. In addition, the PDBfile contains information such as: the symbol table, the structure charts for the file and the host platform; data_standard's and data_alignment's for the file and the host platform; and a modification date.

SYMENT

Just as the defstr type describes entries in the structure chart the syment type describes entries in the symbol table. The syment includes information about the data type of the entry, the number of elements, the dimensions of the entry, and its disk address.

PDBLib by Example

The following code fragments illustrate the functionality of PDBLib. Some of the code is taken from the validation suite and some from the library itself.

Working with PDB files

This routine is taken from the validation suite for PDBLib. In it, a target for the PDB file is chosen with the routine test_target (see the section on PD_target for the definition of this function), a PDB file created, some structures defined, data written, and the file closed. The file is then reopened in append mode, some more data written to the file, and the file is closed again. Finally, the file is opened in read mode, the data read, some comparisons done, and the file is closed. The read and write operations are hidden in this example. The significance of the example is that a PDB file is created, closed, and opened in both append and read-only mode.


 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 test_1(base, tgt, n)
    char *base, *tgt;
    int n;
    {PDBfile *strm;
     char datfile[MAXLINE], fname[MAXLINE];
     int err;
     FILE *fp;
 
 /* target the file as asked */
     test_target(tgt, base, n, fname, datfile);
 
     fp = fopen(fname, "w");
 
 /* create the named file */
     if ((strm = PD_open(datfile, "w")) == NULL)
        {fprintf(fp, "Test couldn't create file %s\r\n", datfile);
         exit(1);};
     fprintf(fp, "File %s created\n", datfile);
 
     prep_test_1_data();
 
 /* make a few defstructs */
     PD_defstr(strm, "l_frame",
               "float x_min", "float x_max", "float y_min",
               "float y_max", LAST);
     PD_defstr(strm, "plot",
               "float x_axis(10)", "float y_axis(10)", "integer npts", 
               "char * label", "l_frame view", LAST);
 
 /* write the test data */
     write_test_1_data(strm);
 
 /* close the file */
     if (!PD_close(strm))
        {fprintf(fp, "Test couldn't close file %s\r\n", datfile);
         exit(1);};
     fprintf(fp, "File %s closed\n", datfile);
 
 /* reopen the file to append */
     if ((strm = PD_open(datfile, "a")) == NULL)
        {fprintf(fp, "Test couldn't open file %s to append\r\n",
                 datfile);
         exit(1);};
     fprintf(fp, "File %s opened to append\n", datfile);
 
     append_test_1_data(strm);
 
 /* close the file after append */
     if (!PD_close(strm))
        {fprintf(fp, "Test couldn't close file %s after append\r\n",
                 datfile);
         exit(1);};
     fprintf(fp, "File %s closed after append\n", datfile);
 
 /* reopen the file */
     if ((strm = PD_open(datfile, "r")) == NULL)
        {fprintf(fp, "Test couldn't open file %s\r\n", datfile);
         exit(1);};
     fprintf(fp, "File %s opened\n", datfile);
 
 /* dump the symbol table */
     dump_test_symbol_table(fp, strm->symtab, 1);
 
 /* read the data from the file */
     read_test_1_data(strm);
 
 /* compare the original data with that read in */
     err = compare_test_1_data(strm, fp);
 
 /* close the file */
     if (!PD_close(strm))
       {fprintf(fp, "Test couldn't close file %s\r\n", datfile);
        exit(1);};
     fprintf(fp, "File %s closed\n", datfile);
 
 /* print it out to stdout */
     print_test_1_data(fp);
 
     fclose(fp);
 
     return(err);}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Writing Data to PDB files

These two routines exemplify the various write routines of PDBLib. In particular, they were built to test the spectrum of write calls. Notice their demonstration of the rules for write operations: the variable must be a pointer to data of the type specified.

The identifiers beginning with `N_' are `#defined' constants whose values are irrelevant to these examples.


 static char
  cs_w,
  ca_w[N_CHAR],
  *cap_w[N_DOUBLE];
 
 static short
  ss_w,
  sa_w[N_INT];
 
 static int
  is_w,
  ia_w[N_INT],
  p_w[N_INT],
  len;
 
 static float
  fs_w,
  fa2_w[N_FLOAT][N_DOUBLE];
 
 static double
  ds_w,
  da_w[N_FLOAT];
 
 static plot
  graph_w;
 
 static l_frame
  view_w;
 
 static lev1
  *tar_w;
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 void write_test_1_data(strm)
    PDBfile *strm;
    {
 
 /* write scalars into the file */
     PD_write(strm, "cs", "char", &cs_w);
     PD_write(strm, "ss", "short", &ss_w);
     PD_write(strm, "is", "integer", &is_w);
     PD_write(strm, "fs", "float", &fs_w);
     PD_write(strm, "ds", "double", &ds_w);
 
 /* write primitive arrays into the file */
     PD_write(strm, "sa(5)", "short", sa_w);
     PD_write(strm, "ia(5)", "integer", ia_w);
 
 /* write structures into the file */
     PD_write(strm, "view", "l_frame", &view_w);
     PD_write(strm, "graph", "plot", &graph_w);
 
     return;}
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 void write_test_2_data(strm)
    PDBfile *strm;
    {
 
    PD_write(strm, "tar", "lev1 *", &tar_w);
 
     return;}
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

Reading Data from PDB files

These two routines exemplify the various read routines of PDBLib. In particular, they were built to test the spectrum of read operations. They read the data written out in the previous example. Notice their demonstration of the rules for read operations: the variable must be a pointer to data of the type specified. This is often a more difficult proposition for reads since the type information isn't supplied in the read call.

The member read operations at the end of the first routine should be studied carefully. They are not the most general read example, but they are among the most useful.

The second routine reads not only the entire structure, but picks out each part individually. It demonstrates the rule about dereferencing pointers in the partial read operation. Study the structures of this example carefully!

The identifiers beginning with `N_' are `#defined' constants whose values are irrelevant to these examples. Also, take for granted that the unspecified variables to contain parts of the structures have the correct declarations.

 
 struct s_lev2
  {char **s;
  int type;};
 
 typedef struct s_lev2 lev2;
 
 struct s_lev1
  {int *a;
  double *b;
  lev2 *c;};
 
 typedef struct s_lev1 lev1;
 
 static char
  cs_r,
  ca_r[N_CHAR],
  *cap_r[N_DOUBLE];
 
 static short
  ss_r,
  sa_r[N_INT];
 
 static int
  is_r,
  ia_r[N_INT];
 
 static float
  fs_r,
  fs_app_r,
  fs_p1_r,
  fs_p2_r,
  fs_p3_r,
  fa2_r[N_FLOAT][N_DOUBLE],
  fa2_app_r[N_FLOAT][N_DOUBLE];
 
 static double
  ds_r,
  da_r[N_FLOAT];
 
 static plot
  graph_r;
 
 static l_frame
  view_r;
 
 static lev1
  *tar_r;
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 void read_test_1_data(strm)
    PDBfile *strm;
    {
 
 /* read the scalar data from the file */
     PD_read(strm, "cs", &cs_r);
     PD_read(strm, "ss", &ss_r);
     PD_read(strm, "is", &is_r);
     PD_read(strm, "fs", &fs_r);
     PD_read(strm, "ds", &ds_r);
 
 /* read the primitive arrays from the file */
     PD_read(strm, "ca", ca_r);
     PD_read(strm, "sa", sa_r);
     PD_read(strm, "ia", ia_r);
     PD_read(strm, "fa2", fa2_r);
     PD_read(strm, "da", da_r);
     PD_read(strm, "cap", cap_r);
 
 /* read the entire structures from the file */
     PD_read(strm, "view", &view_r);
     PD_read(strm, "graph", &graph_r);
 
 /* read the appended data from the file */
     PD_read(strm, "fs_app", &fs_app_r);
     PD_read(strm, "fa2_app", fa2_app_r);
 
 /* struct member test */
     PD_read(strm, "graph.view.x_max", &fs_p2_r);
     PD_read(strm, "view.y_max", &fs_p3_r);
 
     return;}
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 /* READ_TEST_2_DATA - read the test data from the file */
 
 void read_test_2_data(strm)
    PDBfile *strm;
    {do_r = strm->default_offset;
 
     PD_read(strm, "tar", &tar_r);
     PD_read(strm, "p", p_r);
 
     PD_read(strm, "tar(0).a", &ap1);
     PD_read(strm, "tar(1).a", &ap2);
 
     PD_read(strm, "tar(0).a(0)", &aa[0]);
     PD_read(strm, "tar(0).a(1)", &aa[1]);
     PD_read(strm, "tar(1).a(0)", &aa[2]);
     PD_read(strm, "tar(1).a(1)", &aa[3]);
 
     PD_read(strm, "tar(0).b", &bp1);
     PD_read(strm, "tar(1).b", &bp2);
 
     PD_read(strm, "tar(0).b(0)", &ba[0]);
     PD_read(strm, "tar(0).b(1)", &ba[1]);
     PD_read(strm, "tar(1).b(0)", &ba[2]);
     PD_read(strm, "tar(1).b(1)", &ba[3]);
 
     PD_read(strm, "tar(0).c", &cp1);
     PD_read(strm, "tar(1).c", &cp2);
 
     PD_read(strm, "tar(0).c(0)", &ca[0]);
     PD_read(strm, "tar(0).c(1)", &ca[1]);
     PD_read(strm, "tar(1).c(0)", &ca[2]);
     PD_read(strm, "tar(1).c(1)", &ca[3]);
 
     PD_read(strm, "tar(0).c(0).s", &sp1);
     PD_read(strm, "tar(0).c(1).s", &sp2);
     PD_read(strm, "tar(1).c(0).s", &sp3);
     PD_read(strm, "tar(1).c(1).s", &sp4);
 
     PD_read(strm, "tar(0).c(0).s(0)", &tp1);
     PD_read(strm, "tar(0).c(0).s(1)", &tp2);
     PD_read(strm, "tar(0).c(1).s(0)", &tp3);
     PD_read(strm, "tar(0).c(1).s(1)", &tp4);
 
     PD_read(strm, "tar(0).c(0).s(0)(2)", &ta[0]);
     PD_read(strm, "tar(0).c(0).s(1)(1)", &ta[1]);
     PD_read(strm, "tar(0).c(1).s(0)(3)", &ta[2]);
     PD_read(strm, "tar(0).c(1).s(1)(2)", &ta[3]);
 
     PD_read(strm, "tar(1).c(0).s(0)", &tp5);
     PD_read(strm, "tar(1).c(0).s(1)", &tp6);
     PD_read(strm, "tar(1).c(1).s(0)", &tp7);
     PD_read(strm, "tar(1).c(1).s(1)", &tp8);
 
     return;}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Appending Data to PDB file variables

The functions PD_defent, PD_write, and PD_append (and their alternate forms) may be used in several combinations. Users have a variety of scenarios for writing their data. These scenarios are driven by considerations such as: data flow in the application; efficiency of writing the data; or requirements of the application reading the data.

The following examples are taken from the PDB test suite and demonstrate several combinations leaving the rationale to the user. In each example, we are writing a variable IA in three pieces of 5 integers each. The net result is an array which is of dimension (3,5) if the file is set to use row major ordering or (5,3) if the file is set to use column major ordering.

Append Example #1

This is perhaps the simplest case. A variable is written with PD_write and subsequently append to twice with PD_append.
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

 /* WRITE_TEST_1_DATA - write out the data into the PDB file
  *                   - this is write, append, append
  *                   - row major order
  */

 static int write_test_1_data(PDBfile *strm)
    {

 /* write an array into the file */
     if (!PD_write(strm, "ia(1,5)", "integer", ia_w0))
        {printf("IA WRITE FAILED - WRITE_TEST_1_DATA\n");
         return(FALSE);};

 /* append data to ia */
     if (!PD_append(strm, "ia(1:1,0:4)", ia_w1))
        {printf("IA APPEND 1 FAILED - WRITE_TEST_1_DATA\n");
         return(FALSE);};

 /* append more data to ia */
     if (!PD_append(strm, "ia(2:2,0:4)", ia_w2))
        {printf("IA APPEND 2 FAILED - WRITE_TEST_1_DATA\n");
         return(FALSE);};

     return(TRUE);}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Append Example #2

This is the same as Example #1 above except that the file has been set to use column major ordering. Compare the index expressions with those in Example #1.
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

 /* WRITE_TEST_2_DATA - write out the data into the PDB file
  *                   - this is write, append, append
  *                   - row major order
  */

 static int write_test_2_data(PDBfile *strm)
    {

 /* write an array into the file */
     if (!PD_write(strm, "ia(5,1)", "integer", ia_w0))
        {printf("IA WRITE FAILED - WRITE_TEST_2_DATA\n");
         return(FALSE);};

 /* append data to ia */
     if (!PD_append(strm, "ia(0:4,1:1)", ia_w1))
        {printf("IA APPEND 1 FAILED - WRITE_TEST_2_DATA\n");
         return(FALSE);};

 /* append more data to ia */
     if (!PD_append(strm, "ia(0:4,2:2)", ia_w2))
        {printf("IA APPEND 2 FAILED - WRITE_TEST_2_DATA\n");
         return(FALSE);};

     return(TRUE);}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Append Example #3

In this example, some space is reserved for variable. Data is then written to into the reserved space. Subsquently, more data is appended to variable.
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

 /* WRITE_TEST_3_DATA - write out the data into the PDB file
  *                   - this is defent, write, append, append
  *                   - row major order
  */

 static int write_test_3_data(PDBfile *strm)
    {

 /* reserve space for an array in the file */
     if (!PD_defent(strm, "ia(1,5)", "integer"))
        {printf("IA WRITE FAILED - WRITE_TEST_3_DATA\n");
         return(FALSE);};

 /* write data to the reserved space */
     if (!PD_write(strm, "ia(0:0,0:4)", "integer", ia_w0))
        {printf("IA WRITE FAILED - WRITE_TEST_3_DATA\n");
         return(FALSE);};

 /* append data to ia */
     if (!PD_append(strm, "ia(1:1,0:4)", ia_w1))
        {printf("IA APPEND 1 FAILED - WRITE_TEST_3_DATA\n");
         return(FALSE);};

 /* append more data to ia */
     if (!PD_append(strm, "ia(2:2,0:4)", ia_w2))
        {printf("IA APPEND 2 FAILED - WRITE_TEST_3_DATA\n");
         return(FALSE);};

     return(TRUE);}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Append Example #4

In this example, some space is reserved for variable. Data is then written to into the reserved space. Subsquently, another block of space is reserved for the variable and later filled in with calls to PD_write.
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

 /* WRITE_TEST_4_DATA - write out the data into the PDB file
  *                   - this is defent, write, defent, write, write
  *                   - column major order
  */

 static int write_test_4_data(PDBfile *strm)
    {

 /* reserve space for an array in the file */
     if (!PD_defent(strm, "ia(5,1)", "integer"))
        {printf("IA DEFENT 1 FAILED - WRITE_TEST_4_DATA\n");
         return(FALSE);};

 /* write data to the reserved space */
     if (!PD_write(strm, "ia(0:4,0:0)", "integer", ia_w0))
        {printf("IA WRITE FAILED - WRITE_TEST_4_DATA\n");
        return(FALSE);};

 /* reserve more space for ia */
     if (!PD_defent(strm, "ia(0:4,1:2)", "integer"))
        {printf("IA DEFENT 2 FAILED - WRITE_TEST_4_DATA\n");
         return(FALSE);};

 /* write data to the some of the additional reserved space */
     if (!PD_write(strm, "ia(0:4,1:1)", "integer", ia_w1))
        {printf("IA APPEND 1 FAILED - WRITE_TEST_4_DATA\n");
         return(FALSE);};

 /* write data to the rest of the additional reserved space */
     if (!PD_write(strm, "ia(0:4,2:2)", "integer", ia_w2))
        {printf("IA APPEND 2 FAILED - WRITE_TEST_4_DATA\n");
         return(FALSE);};

     return(TRUE);}

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 

Inquiries in PDBLib

The following fragments show how to obtain information about PDB files and their contents.

 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 myread(file, name, var, offset, number)
    PDBfile *file;
    char *name;
    void *var;
    long offset, number;
    {long addr, num;
     char *token, *type, memb[MAXLINE];
     dimdes *dims;
     syment *ep;
 
     strcpy(memb, name);
     token = strtok(memb, ".([");
 
 /* look up the variable name */
     ep = PD_query_entry(file, token, NULL);
     if (ep == NULL)
        printf("%s", PD_get_error());
 
     addr = PD_entry_address(ep);
     dims = PD_entry_dimensions(ep);
     num  = PD_entry_number(ep);
     type = PD_entry_type(ep);
 
 /* with ep in hand, we know the variable type, number of elements,
  * dimensions, and disk address
  */
               .
               .
               .
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 
 _PD_wr_leaf(file, var, nitems, type)
    PDBfile *file;
    char *var;
    long nitems;
    char *type;
    {char *svar;
     int size;
     FILE *fp;
     defstr *dp;
     memdes *desc, *mem_lst;
 
     fp = file->stream;
            .
            .
            .
 
 /* dispatch all other writes */
     if (file->conversions)
            .
            .
            .
 
 /* obtain a pointer to the defstr associated with type */
     dp = PD_inquire_host_type(file, type);
     if (dp == NULL)
        printf("%s", PD_get_error());
 
 /* if the structure has any pointered members loop over the members */
     if (dp->n_indirects && ((mem_lst = dp->members) != NULL))
        {size = dp->size;
         for (svar = var, offset = 0L, i = 0L; i <; nitems; i++)
             {for (desc = mem_lst; desc != NULL; desc = desc->next)
                  { ... };
              svar += size;};};
            .
            .
            .
 
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/

Browsing PDB files

The following fragment shows how to browse around in PDB files. Note the use of PD_ls. What this example doesn't show is checking for the directory type and perhaps using PD_cd to move to other directories.


    int i, nd, ne;
    long ni;
    long *dims;
    char **names, *fname, *type;
    syment *ep;
    PDBfile *file;

    fname = "/tmp/fubar.pdb";
    file = PD_open(fname, "r");
    if (file == NULL)
       {printf("Error opening %s\n", fname);
	exit(1);};

    printf("\nSymbol Table:\n");

/* print contents of symbol table */
    names = PD_ls(file, NULL, NULL, &ne);
    for (i = 0; i < ne; i++)
	{if (names[i] != NULL)
            {ep = PD_query_entry(file, names[i], NULL);
	     rv = PD_get_entry_info(ep, &type, &ni, &nd, &dims);
	     if (rv)
	        {printf("%20s %10s %8ld %2d (%p)\n",
			names[i], type, ni, nd, dims);
		 PD_free_entry_info(type, dims);};};};

    SFREE(names);

/* close file */
    PD_close(file);

Writing PM_mappings with PFWMAP

The following fragment shows how to write a PM_mapping to a PDB file from a FORTRAN program. This example uses PFWMAP. PFWMAP writes out both domain and range as a complete mapping. The drawback to this approach is that many mappings might have the same domain which would be written out over and over again. This could lead to unacceptably large data files. See the next example for a more space saving approach.

 
 c-----------------------------------------------------------------
 c-----------------------------------------------------------------

  subroutine sxdmp(namesx, namelen)
 
 c traverse plot list to make dumps suitable for sx
 
  integer pfopen, pfclos, pfgerr, pfwmap, pfwset, pfwran
  integer zscanleq
  
  integer pderr(32), rp(6), dp(6)
  integer fileid, pim, dmnsn
 
  double precision rm(nsavept), dm(nsavept)
 
 c ... set up
             .
             .
             .
 
 c ... open the file
  fileid = pfopen(namelen, namesx, 'w')
  if (fileid .eq. -1) then
     iplpderr = pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
 
  pim = 0
 
 c ... loop over plots
  do ...
 
 c ... setup domain
  dname = <;domain name>
  dp(1) = <;length of domain name>
 
  select case (dmnsn)
  case ('d2r1')
     dp(2) = 2
     dp(3) = 2
     dp(4) = nr
     dp(5) = kmax
     dp(6) = lmax
     call zmovewrd(dm(1), x2d, nr)
     call zmovewrd(dm(nr+1), y2d, nr)
  case ('d1r1')
     dp(2) = 1
     dp(3) = 1
     dp(4) = nr
     dp(5) = nr
     call zmovewrd(dm(1), <;domain data>, nr)
  endselect
 
 c ... set up range
  rname = <;range name>
  rp(1) = <;length of range name>
 
  rp(2) = dp(2)
  rp(3) = 1
  rp(4) = nr
  rp(5) = dp(5)
  rp(6) = dp(6)
  call zmovewrd(rm(1), <;range data>, nr)
 
 c ... write the mapping
  ierr = pfwmap(fileid, dname, dp, dm, rname, rp, rm, pim)
  if (ierr.eq.0) then
     pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
  pim = pim + 1
  repeat
 
 c ... close the file
  icloseok = pfclos(fileid)
  if (icloseok.eq.0) then
     pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
 
  return
  end

 c-----------------------------------------------------------------
 c-----------------------------------------------------------------

Writing PM_mappings with PFWSET and PFWRAN

The following fragment shows how to write a PM_mapping to a PDB file from a FORTRAN program. This example uses PFWSET and PFWRAN. With PFWSET and PFWRAN an application can write mappings in the most space efficient way. Instead of writing the same domains over and over again as would be done with PFWMAP, the application can select the unique domains and write them out with PFWSET. Then all mappings can be written using PFWRAN which writes out a PM_mapping with a null domain. The post processing tools (such as PDBView) reconstruct the complete PM_mapping by looking for the domain as a variable with the same name as the domain component of the mapping name. This approach is clearly a little more involved than using PFWMAP and application developers should weigh the advantages and disadvantages before selecting one method over the other. See the previous example for an illustration of the use of PFWMAP.

 
 c-----------------------------------------------------------------
 c-----------------------------------------------------------------

  subroutine sxdmp(namesx, namelen)
 
 c traverse plot list to make dumps suitable for sx
 
  integer pfopen, pfclos, pfgerr, pfwmap, pfwset, pfwran
  integer zscanleq
  
  integer pderr(32), rp(6), dp(6)
  integer fileid, pim, dmnsn
 
  double precision rm(nsavept), dm(nsavept)
 
 c ... set up
             .
             .
             .
 
 c ... open the file
  fileid = pfopen(namelen, namesx, 'w')
  if (fileid .eq. -1) then
     iplpderr = pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
 
  pim = 0
 
 c ... loop over plots
  do ...
 
 c ... setup domain
  dname = <;domain name>
  dp(1) = <;length of domain name>
 
  select case (dmnsn)
  case ('d2r1')
     dp(2) = 2
     dp(3) = 2
     dp(4) = nr
     dp(5) = kmax
     dp(6) = lmax
     call zmovewrd(dm(1), x2d, nr)
     call zmovewrd(dm(nr+1), y2d, nr)
  case ('d1r1')
     dp(2) = 1
     dp(3) = 1
     dp(4) = nr
     dp(5) = nr
     call zmovewrd(dm(1), <;domain data>, nr)
  endselect
 
  if <;unique domain> then
     ierr = pfwset(fileid, dname, dp, dm)
     if (ierr.eq.0) then
        iplpderr = pfgerr(nchr, pderr)
        call errproc(pderr, nchr, 0, 0)
     endif
  endif
 
 c ... set up range
  rname = <;range name>
  rp(1) = <;length of range name>
 
  rp(2) = dp(2)
  rp(3) = 1
  rp(4) = nr
  rp(5) = dp(5)
  rp(6) = dp(6)
  call zmovewrd(rm(1), <;range data>, nr)
 
 c ... write out range
  ierr = pfwran(fileid, dname, dp(1), rname, rp, rm, pim)
  if (ierr.eq.0) then
     pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
  pim = pim+1
  repeat
 
 c ... close the file
  icloseok = pfclos(fileid)
  if (icloseok.eq.0) then
     pfgerr(nchr, pderr)
     call errproc(pderr, nchr, 0, 0)
  endif
 
  return
  end

 c-----------------------------------------------------------------
 c-----------------------------------------------------------------

SMP Parallel Example

This section will illustrate the use of PDBLib in a threaded program.


/*
 * PDSMP.C - Test smp i/o in PDBLib
 *
 * Source Version: 9.0
 * Software Release #: UCRL-CODE-155969
 *
 */

#include "cpyright.h"

#include "pdb.h"

#define NPTS 10

#define check_myplot1(xplot, rxplot)                                                                 \
        {int i;                                                                                      \
         if (strcmp(xplot.label, rxplot.label) != 0)                                                 \
            {printf("xplot.label differs from rxplot.label in %s\n", sname1);                        \
             printf("xplot.label: %s, rxplot.label: %s\n", xplot.label, rxplot.label);               \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot.view->x_min != rxplot.view->x_min)                                                \
            {printf("xplot.view->xmin differs from rxplot.view->xmin in %s\n", sname1);              \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot.view->x_max != rxplot.view->x_max)                                                \
            {printf("xplot.view->x_max differs from rxplot.view->x_max in %s\n", sname1);            \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot.view->y_min != rxplot.view->y_min)                                                \
            {printf("xplot.view->y_min differs from rxplot.view->y_min in %s\n", sname1);            \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot.view->y_max != rxplot.view->y_max)                                                \
            {printf("xplot.view->y_max differs from rxplot.view->y_max in %s\n", sname1);            \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot.npts != rxplot.npts)                                                              \
            {printf("xplot.npts differs from rxplot.npts in %s\n", sname1);                          \
             exit(1);}                                                                               \
                                                                                                     \
         for (i = 0; i < 10; i++)                                                                    \
             if (xplot.x_axis[i] != rxplot.x_axis[i])                                                \
                {printf("xplot.x_axis[%d] differs from rxplot.x_axis[%d] in %s\n", i, i, sname1);    \
                exit(1);};}            

#define check_myplot2(xplot, rxplot)                                                                 \
        {int i;                                                                                      \
         if (strcmp(xplot->label, rxplot->label) != 0)                                                   \
            {printf("xplot->label differs from rxplot->label in %s\n", sname1);                      \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot->view->x_min != rxplot->view->x_min)                                              \
            {printf("xplot->view->xmin differs from rxplot->view->xmin in %s\n", sname1);            \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot->view->x_max != rxplot->view->x_max)                                              \
            {printf("xplot->view->x_max differs from rxplot->view->x_max in %s\n", sname1);          \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot->view->y_min != rxplot->view->y_min)                                              \
            {printf("xplot->view->y_min differs from rxplot->view->y_min in %s\n", sname1);          \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot->view->y_max != rxplot->view->y_max)                                              \
            {printf("xplot->view->y_max differs from rxplot->view->y_max in %s\n", sname1);          \
             exit(1);}                                                                               \
                                                                                                     \
         if (xplot->npts != rxplot->npts)                                                            \
            {printf("xplot->npts differs from rxplot->npts in %s\n", sname1);                        \
             exit(1);}                                                                               \
                                                                                                     \
         for (i = 0; i < 10; i++)                                                                    \
             if (xplot->x_axis[i] != rxplot->x_axis[i])                                              \
                {printf("xplot->x_axis[%d] differs from rxplot->x_axis[%d] in %s\n", i, i, sname1);  \
                exit(1);};}        

struct s_l_frame
   {float x_min;
    float x_max;
    float y_min;
    float y_max;};

typedef struct s_l_frame l_frame;

struct s_plot
   {float x_axis[NPTS];
    float y_axis[NPTS];
    int npts;
    char *label;
    l_frame *view;};

typedef struct s_plot myplot;

float d[100], d2[100];

int   j[100], j2[100];
int n_iter = 10;

myplot mypl;

PDBfile *file, *file2;

int
 ok_count;

void *writeit(void *x);
void *writeit2(void *x);
void *readit(void *x);
void *readit2(void *x);
void print_help();

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------    */

/* Write variables to the already opened file.  The number of variables written */
/* is a function of the number of iterations specified.                         */

void *writeit(arg)
   void *arg;
   {int i, n;
    myplot *xp;
    char sname1[100], sname2[100], sname3[100], suffix[10];

    xp = FMAKE(myplot, "Writeit:xp");
    xp->view = FMAKE(l_frame, "Writeit:xp->view");

    xp->label = SC_strsavef("Dynamic XP label", "char*:writeit:xp");
    xp->view->x_min = 0.2;
    xp->view->x_max = 0.9;
    xp->view->y_min = 0.33;
    xp->view->y_max = 0.99;
    xp->npts       = 10;

    for (i = 0; i < 10; i++)
        xp->x_axis[i] = xp->y_axis[i] = (float)i * 4.0;
         
    strcpy(sname1, "mypl_wr1a"); 
    strcpy(sname2, "xpl_wr1a"); 
    strcpy(sname3, "mypl_wr1b"); 

    for (n = 0; n < n_iter; n++)    
        {sprintf(suffix, "%d", n);

         strcpy(sname1+9, suffix);
         strcpy(sname2+8, suffix);
         strcpy(sname3+9, suffix);

        if (!PD_write(file, sname1, "myplot", &mypl))
           {printf("Error writing %s-exiting\n", sname1);
            exit(1);}

        if (!PD_write(file, sname2, "myplot *", &xp))
           {printf("Error writing %s-exiting\n", sname2);
            exit(1);}

        if (!PD_write(file, sname3, "myplot", &mypl))
           {printf("Error writing %s-exiting\n", sname3);
            exit(1);};}

    ok_count++;

    SFREE(xp->label);
    SFREE(xp->view);
    SFREE(xp);

    return(NULL);}
     
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

void *writeit2(arg)
   void *arg;
   {int i, n;
    char sname1[100], sname2[100], suffix[100];
    myplot xplot;

    xplot.label = SC_strsavef("Myplot Xplot label", "char*:writeit2:xplot");
    xplot.view = FMAKE(l_frame, "Xplot.view:writeit2");

    xplot.view->x_min = 0.15;
    xplot.view->x_max = 0.85;
    xplot.view->y_min = 0.25;
    xplot.view->y_max = 0.75;
    xplot.npts       = 10;

    for (i = 0; i < 10; i++)
        xplot.x_axis[i] = xplot.y_axis[i] = (float)i;

    strcpy(sname1, "mypl_wr2a"); 
    strcpy(sname2, "xpl_wr2a"); 

    for (n = 0; n < n_iter; n++)
        {sprintf(suffix, "%d", n);

         strcpy(sname1+9, suffix);
         strcpy(sname2+8, suffix);

         if (!PD_write(file, sname1, "myplot", &xplot))
            {printf("Error writing %s-exiting\n", sname1);
             exit(1);}       

         if (!PD_write(file, sname2, "myplot", &xplot))
            {printf("Error writing %s-exiting\n", sname2);
             exit(1);};}

    ok_count++;

    SFREE(xplot.label);
    SFREE(xplot.view);
 
    return NULL;}
     
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

void *readit(arg)
   void *arg;
   {int i, n;
    myplot *xp, *rxp, rmypl;
    char sname1[100], sname2[100], sname3[100], suffix[10];

    xp = FMAKE(myplot, "Writeit:xp");
    xp->view = FMAKE(l_frame, "Writeit:xp->view");

    xp->label = SC_strsavef("Dynamic XP label", "char*:writeit:xp");
    xp->view->x_min = 0.2;
    xp->view->x_max = 0.9;
    xp->view->y_min = 0.33;
    xp->view->y_max = 0.99;
    xp->npts       = 10;

    for (i = 0; i < 10; i++)
        xp->x_axis[i] = xp->y_axis[i] = (float)i * 4.0;

    strcpy(sname1, "mypl_wr1a"); 
    strcpy(sname2, "xpl_wr1a"); 
    strcpy(sname3, "mypl_wr1b"); 

    for (n = 0; n < n_iter; n++)    
        {sprintf(suffix, "%d", n);

         strcpy(sname1+9, suffix);
         strcpy(sname2+8, suffix);
         strcpy(sname3+9, suffix);

        if (!PD_read(file, sname1, &rmypl))
           {printf("Error writing %s-exiting\n", sname1);
            exit(1);}

/* compare with original */
        check_myplot1(mypl, rmypl);

/* free the memory */    
        SFREE(rmypl.label);
        SFREE(rmypl.view);

        if (!PD_read(file, sname2, &rxp))
           {printf("Error writing %s-exiting\n", sname2);
            exit(1);}

/* compare with original */
        check_myplot2(xp, rxp);

/* free the memory   */ 
        SFREE(rxp->label);
        SFREE(rxp->view);
        SFREE(rxp);

        if (!PD_read(file, sname3, &rmypl))
           {printf("Error writing %s-exiting\n", sname3);
            exit(1);};

/* compare with original */
	 check_myplot1(mypl, rmypl);

/* free the memory    */
	 SFREE(rmypl.label);
	 SFREE(rmypl.view);};

    ok_count++;

    SFREE(xp->label);
    SFREE(xp->view);
    SFREE(xp);

    return NULL;}
     
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

void *readit2(arg)
   void *arg;
   {int i, n;
    char sname1[100], sname2[100], suffix[100];
    myplot xplot, rxplot;

    xplot.label = SC_strsavef("Myplot Xplot label", "char*:writeit2:xplot");
    xplot.view = FMAKE(l_frame, "Xplot.view:writeit2");

    xplot.view->x_min = 0.15;
    xplot.view->x_max = 0.85;
    xplot.view->y_min = 0.25;
    xplot.view->y_max = 0.75;
    xplot.npts       = 10;

    for (i = 0; i < 10; i++)
        xplot.x_axis[i] = xplot.y_axis[i] = (float)i;

    strcpy(sname1, "mypl_wr2a"); 
    strcpy(sname2, "xpl_wr2a"); 

    for (n = 0; n < n_iter; n++)
        {sprintf(suffix, "%d", n);

         strcpy(sname1+9, suffix);
         strcpy(sname2+8, suffix);

         if (!PD_read(file, sname1, &rxplot))
            {printf("Error writing %s-exiting\n", sname1);
             exit(1);}       

/* compare with original */
         check_myplot1(xplot, rxplot);

/* free the memory    */
         SFREE(rxplot.label);
         SFREE(rxplot.view);

         if (!PD_read(file, sname2, &rxplot))
            {printf("Error writing %s-exiting\n", sname2);
             exit(1);};

/* compare with original */
         check_myplot1(xplot, rxplot);

/* free the memory    */
	 SFREE(rxplot.label);
	 SFREE(rxplot.view);};

    ok_count++;

    SFREE(xplot.label);
    SFREE(xplot.view);
 
    return(NULL);}
     
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PRINT_HELP - print a help message */

void print_help()
   {

    PRINT(STDOUT, "\nPDSMP - run basic PDB smp test\n\n");
    PRINT(STDOUT, "Usage: pdsmp [-h] [-i n]\n");
    PRINT(STDOUT, "\n");
    PRINT(STDOUT, "       h - print this help message and exit\n");
    PRINT(STDOUT, "       i - set number of iterations in reading and writing loops to n\n");
    PRINT(STDOUT, "\n");

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

main(argc, argv)
   int argc;
   char **argv;
   {int nthreads;
    int i;
    int nt[2];
    void *(*fnc[2])(void *);

    for (i = 1; i < argc; i++)
        {if (argv[i][0] == '-')
            {switch (argv[i][1])
                {case 'h' :
		      print_help();
		      return(1);

                 case 'i' :
		      n_iter = atol(argv[++i]);
		      break;};}
         else
            break;};

    ok_count = 0;

    printf("%d iterations per thread\n", n_iter);

/* load up the output arrays */
    for (i = 0; i < 100; i++)
	{d[i] = d2[i] = (float) i;
         j[i] = j2[i] = i;}

    nthreads = 5;

/* initialize PDBLib for 5 threads (includes main thread) */
    PD_init_threads(nthreads, NULL);

/* create the output file */
    if ((file = PD_open("ptest.pdb", "w")) == NULL)
       {printf("Error creating ptest.pdb\n");
	return(1);};

/* define the structures to the library */
    PD_defstr(file, "l_frame",
              " float x_min",
              "float x_max",
              "float y_min",
              "float y_max",
              LAST);

    PD_defstr(file, "myplot",
              "float x_axis(10)",
              "float y_axis(10)",
              "integer npts", 
              "char * label",
              "l_frame * view",
               LAST);

/* put some values in the structures */
    mypl.label = SC_strsavef("Myplot MYPL label", "PDPTST:main mypl");
    mypl.view  = FMAKE(l_frame, "Myplot MYPL view");

    mypl.view->x_min = 0.1;
    mypl.view->x_max = 0.8;
    mypl.view->y_min = 0.2;
    mypl.view->y_max = 0.7;
    mypl.npts       = 10;
   
    for (i = 0; i < 10; i++)
        mypl.x_axis[i] = mypl.y_axis[i] = (float)i;

    nt[0] = 1;
    nt[1] = 1;

/* two threads write the file */
    fnc[0] = writeit;
    fnc[1] = writeit2;
    SC_do_threads(2, nt, fnc, NULL, NULL);

/* flush the tables to the file */
    if (!PD_flush(file))
       {printf("Error flushing file before reads\n");
        return(1);};

/* two threads read the file */
    fnc[0] = readit;
    fnc[1] = readit2;
    SC_do_threads(2, nt, fnc, NULL, NULL);

/* close file */
    PD_close(file);

    return((ok_count != 4));}


MPI Parallel Example

This section illustrates the use of PDBLib in an MPI program.

/*
 * PDDMP.C - Test dmp i/o in PDBLib
 *
 * Source Version: 9.0
 * Software Release #: UCRL-CODE-155969
 *
 */

#include "cpyright.h"

#include "pdb.h"

#define N_INT 100
#define N_FLOAT 100
#define N_DOUBLE 100
#define N_PTS 10
#define N_ITER 10

#define TEST_TYPE(_x_)                                         \
   {if (_x_ == MPI_COMM_SELF)                                  \
       printf("MPI_COMM_SELF test\n");                         \
    else                                                       \
       printf("MPI_COMM_WORLD test\n");}

#define check_myplot1(xplot, rxplot, _comm_)                                                                 \
        {int i;                                                                                              \
         if (strcmp(xplot.label, rxplot.label) != 0)                                                         \
            {printf("xplot.label differs from rxplot.label in %s\n", name);                                  \
             printf("xplot.label: %s, rxplot.label: %s\n", xplot.label, rxplot.label);                       \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         if (xplot.view->x_min != rxplot.view->x_min)                                                        \
            {printf("xplot.view->xmin differs from rxplot.view->xmin in %s\n", name);                        \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         if (xplot.view->x_max != rxplot.view->x_max)                                                        \
            {printf("xplot.view->x_max differs from rxplot.view->x_max in %s\n", name);                      \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         if (xplot.view->y_min != rxplot.view->y_min)                                                        \
            {printf("xplot.view->y_min differs from rxplot.view->y_min in %s\n", name);                      \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         if (xplot.view->y_max != rxplot.view->y_max)                                                        \
            {printf("xplot.view->y_max differs from rxplot.view->y_max in %s\n", name);                      \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         if (xplot.npts != rxplot.npts)                                                                      \
            {printf("xplot.npts differs from rxplot.npts in %s\n", name);                                    \
             TEST_TYPE(_comm_);}                                                                             \
                                                                                                             \
         for (i = 0; i < N_PTS; i++)                                                                         \
             if (xplot.x_axis[i] != rxplot.x_axis[i])                                                        \
                {printf("xplot.x_axis[%d] differs from rxplot.x_axis[%d] in %s\n", i, i, name);              \
                TEST_TYPE(_comm_);};}     

struct s_l_frame
   {float x_min;
    float x_max;
    float y_min;
    float y_max;};

typedef struct s_l_frame l_frame;

struct s_plot
   {float x_axis[N_PTS];
    float y_axis[N_PTS];
    int npts;
    char *label;
    l_frame *view;};

typedef struct s_plot myplot;
    
static float x[100], xr[100];
static int *pi1, *pi1r;
static float *pf1, *pf1r;
static myplot mypl, myplr;

static void write_data(char *path, int rank, int size, MPI_Comm comm);
static void read_data(char *path, int rank, int size, MPI_Comm comm);

main(argc, argv)
   int argc;
   char **argv;
   {int rank, size;
    char path[MAXLINE];
    PDBfile *file;


    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

/*
   if there is a command line argument it is the path of the directory
   to write in.
*/
    if (argc > 1)
       strcpy(path, argv[1]);
    else
       strcpy(path, "/p/gb1/minner");
       
/* 
   initialize PDBLib for MPI 
   master process:    0
   number of threads: 1
   tid function:      NULL
*/
    PD_init_mpi(0, 1, NULL);

    write_data(path, rank, size, MPI_COMM_WORLD);

    write_data(path, rank, size, MPI_COMM_SELF);

    read_data(path, rank, size, MPI_COMM_WORLD);

    read_data(path, rank, size, MPI_COMM_SELF);

    PD_term_mpi();

    MPI_Finalize();

    return(0);}

/*--------------------------------------------------------------------------    */
/*--------------------------------------------------------------------------*/

static void write_data(path, rank, size, comm)
   char *path;
   int rank, size;
   MPI_Comm comm;
   {char name[MAXLINE], temp[MAXLINE];
    char sx_axis[MAXLINE], sy_axis[MAXLINE];
    PDBfile *file;
    float frank;
    int i, nwrite;

    strcpy(name, path);
    strcat(name, "/");

    if (comm != MPI_COMM_SELF)
       strcat(name, "test_mult.pdb");
    else
       {sprintf(temp, "test_single%d.pdb", rank);
        strcat(name, temp);}

/* create the output file */
    if ((file = PD_mp_create(name, comm))
         == NULL)
       {printf("Error creating %s\n", name);
	return;};

/* define the structures to the library */
    PD_defstr(file, "l_frame",
              " float x_min",
              "float x_max",
              "float y_min",
              "float y_max",
              LAST);

    sprintf(sx_axis, "float x_axis(%d)", N_PTS);
    sprintf(sy_axis, "float y_axis(%d)", N_PTS);

    PD_defstr(file, "myplot",
              sx_axis,
              sy_axis,
              "integer npts", 
              "char * label",
              "l_frame * view",
               LAST);

/* put some values in the structures */
    mypl.label = SC_strsavef("Myplot MYPL label", "PDDMP:main mypl");
    mypl.view  = FMAKE(l_frame, "Myplot MYPL view");

    mypl.view->x_min = 0.1;
    mypl.view->x_max = 0.8;
    mypl.view->y_min = 0.2;
    mypl.view->y_max = 0.7;
    mypl.npts       = N_PTS;
   
    for (i = 0; i < N_PTS; i++)
        mypl.x_axis[i] = mypl.y_axis[i] = (float)i;

/* write a struct */
    sprintf(name, "myplot_%d", rank);
    if (!PD_write(file, name, "myplot", &mypl))
       {printf("Error writing mypl: process %d\n", rank);}

/* write an integer */
    sprintf(name, "rank_%d", rank);
    if (!PD_write(file, name, "integer", &rank))
       {printf("Error writing rank: process %d\n", rank);}

/* write a float */
    frank = rank;
    sprintf(name, "frank_%d", rank);
    if (!PD_write(file, name, "float", &frank))
       {printf("Error writing frank: process %d\n", rank);}

/* write an int array */
    pi1 = FMAKE_N(int, N_INT, "WRITE_DATA:pi1");
    if (pi1 == NULL)
       {printf("Error allocating pi1, process %d--quitting\n", rank);
        exit(1);}
    for (i = 0; i < N_INT; i++)
        pi1[i] = rank * i;
    sprintf(name, "pi1_%d", rank);
    if (!PD_write(file, name, "int *", &pi1))
       {printf("Error writing pi1: process %d\n", rank);}

/* write an float array */
    pf1 = FMAKE_N(float, N_FLOAT, "WRITE_DATA:pf1");
    if (pf1 == NULL)
       {printf("Error allocating pf1, process %d--quitting\n", rank);
        exit(1);}
    for (i = 0; i < N_FLOAT; i++)
        pf1[i] = (float)(rank * i);
    sprintf(name, "pf1_%d", rank);
    if (!PD_write(file, name, "float *", &pf1))
       {printf("Error writing pf1: process %d\n", rank);}

/* try a PD_defent */
    if (!PD_defent(file, "x[100]", "float"))
       {printf("PD_defent failed for x[100], process %d\n",
                rank);}

    nwrite = (comm == MPI_COMM_SELF) ? 100 : 100 / size;
    for (i = 0; i < 100; i++)
        x[i] = (float)rank;

    if (comm != MPI_COMM_SELF)
       sprintf(name, "x[%d:%d]", rank*nwrite, (rank+1)*nwrite - 1);
    else
       strcpy(name, "x[0:99]");

    if (!PD_write(file, name, "float", x))
       {printf("Error writing x, process %d\n", rank);}

/* close file */
    PD_close(file);
    
    return;}
/*--------------------------------------------------------------------------    */
/*--------------------------------------------------------------------------*/

static void read_data(path, rank, size, comm)
   char *path;
   int rank, size;
   MPI_Comm comm;
   {char name[MAXLINE], temp[MAXLINE];
    PDBfile *file;
    int rankr;
    float frank;
    int i, nread;

    strcpy(name, path);
    strcat(name, "/");

    if (comm != MPI_COMM_SELF)
       strcat(name, "test_mult.pdb");
    else
       {sprintf(temp, "test_single%d.pdb", rank);
        strcat(name, temp);}

/* open the input file */
    if ((file = PD_mp_open(name, "r", comm))
         == NULL)
       {printf("Error opening %s, rank: %d\n", name, rank);
        TEST_TYPE(comm); 
	return;};

/* read a struct */
    sprintf(name, "myplot_%d", rank);
    if (!PD_read(file, name, &myplr))
       {printf("Error reading mypl: process %d\n", rank);
        TEST_TYPE(comm);}

    check_myplot1(mypl, myplr, comm);

/* read an integer */
    sprintf(name, "rank_%d", rank);
    if (!PD_read(file, name, &rankr))
       {printf("Error reading rank: process %d\n", rank);
        TEST_TYPE(comm);}

    if (rankr != rank)
       {printf("Error: rankr != rank: process %d\n", rank);
        TEST_TYPE(comm);}

/* read a float */
    sprintf(name, "frank_%d", rank);
    if (!PD_read(file, name, &frank))
       {printf("Error reading frank: process %d\n", rank);
        TEST_TYPE(comm);}

    if (frank != (float)rank)
       {printf("Error: frank != rank: process %d\n", rank);
        TEST_TYPE(comm);}

/* read an int *array */
    sprintf(name, "pi1_%d", rank);
    if (!PD_read(file, name, &pi1r))
       {printf("Error reading pi1r: process %d\n", rank);
        TEST_TYPE(comm);}

    for (i = 0; i < N_INT; i++)
        if (pi1r[i] != pi1[i])
           {printf("Error: pi1r[%d] != pi1[%d], pi1r[%d] = %d, pi1[%d] = %d",
                    i, i, i, pi1r[i], i, pi1[i]);
            printf(" Process %d\n", rank);
            TEST_TYPE(comm);
            break;}

/* read a float array */
    sprintf(name, "pf1_%d", rank);
    if (!PD_read(file, name, &pf1r))
       {printf("Error reading pf1: process %d\n", rank);}

    for (i = 0; i < N_FLOAT; i++)
        if (pf1r[i] != pf1[i])
           {printf("Error: pf1r[%d] != pf1[%d], pf1r[%d] = %d, pf1[%d] = %d",
                    i, i, i, pf1r[i], i, pf1[i]);
            printf(" Process %d\n", rank);
            TEST_TYPE(comm);
            break;}

/* read the PD_defented array */
    nread = 100;
    strcpy(name, "x[0:99]");

    if (!PD_read(file, name, xr))
       {printf("Error reading x, process %d\n", rank);
        TEST_TYPE(comm);}

    if (comm == MPI_COMM_SELF)
       {for (i = 0; i < 100; i++)
            if (xr[i] != x[i])
               {printf("Error: xr[%d] != x[%d], xr[%d] = %d, x[%d] = %d\n",
                       i, i, i, xr[i], i, x[i]);
                printf(" Process %d\n", rank);
                TEST_TYPE(comm);
                break;};}
    else
       {int nchunk = 100 / size;
        for (i = rank*nchunk; i < (rank+1)*nchunk; i++)
            if (xr[i] != (float)rank)
               {printf("Error: xr[%d] != rank, xr[%d] = %f, rank = %d\n",
                       i, i, xr[i], rank);
                printf(" Process %d\n", rank);
                TEST_TYPE(comm);
                break;};}

/* close file */
    PD_close(file);
    
    return;}

Related Documentation

PDBLib is one part of a collection of libraries called PACT. PDBLib uses the SCORE library in PACT for memory management, hash table, and string handling support. Interested readers should consult the SCORE manual as well as the PDBView manual, the ULTRA II manual, and the PANACEA manual for more information on how PDBLib is used.

The list of PACT documents is:

PACT User’s Guide

SCORE User’s Manual

PPC User’s Manual

PML User’s Manual

PDBLib User’s Manual

PGS User’s Manual

PANACEA User’s Manual

ULTRA II User’s Manual

PDBDiff User’s Manual

PDBView User’s Manual

SX User’s Manual


For questions and comments, please contact the PACT Development Team.
Last Updated: 03/04/2007
llnl logo  
  UCRL-CODE-155969| Privacy & Legal Notice
Last modified: February 22, 2007   
  
Contact: wci-webteam@llnl.gov