22.10.2014 Views

in NetCDF Fortran 90 - Unidata - University Corporation for ...

in NetCDF Fortran 90 - Unidata - University Corporation for ...

in NetCDF Fortran 90 - Unidata - University Corporation for ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

<strong>NetCDF</strong> Version 3.6.0<br />

December 2004<br />

Russ Rew, Glenn Davis, Steve Emmerson, and Harvey Davies<br />

<strong>Unidata</strong> Program Center


Copyright c○ 2004 <strong>University</strong> <strong>Corporation</strong> <strong>for</strong> Atmospheric Research<br />

Permission is granted to make and distribute verbatim copies of this manual provided that<br />

the copyright notice and these paragraphs are preserved on all copies. The software and any<br />

accompany<strong>in</strong>g written materials are provided “as is” without warranty of any k<strong>in</strong>d. UCAR<br />

expressly disclaims all warranties of any k<strong>in</strong>d, either expressed or implied, <strong>in</strong>clud<strong>in</strong>g but not<br />

limited to the implied warranties of merchantability and fitness <strong>for</strong> a particular purpose.<br />

The <strong>Unidata</strong> Program Center is managed by the <strong>University</strong> <strong>Corporation</strong> <strong>for</strong> Atmospheric<br />

Research and sponsored by the National Science Foundation. Any op<strong>in</strong>ions, f<strong>in</strong>d<strong>in</strong>gs, conclusions,<br />

or recommendations expressed <strong>in</strong> this publication are those of the author(s) and<br />

do not necessarily reflect the views of the National Science Foundation.<br />

Mention of any commercial company or product <strong>in</strong> this document does not constitute an<br />

endorsement by the <strong>Unidata</strong> Program Center. <strong>Unidata</strong> does not authorize any use of<br />

<strong>in</strong><strong>for</strong>mation from this publication <strong>for</strong> advertis<strong>in</strong>g or publicity purposes.


i<br />

Table of Contents<br />

1 Use of the <strong>NetCDF</strong> Library . . . . . . . . . . . . . . . . 1<br />

1.1 Creat<strong>in</strong>g a <strong>NetCDF</strong> Dataset. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

1.2 Read<strong>in</strong>g a <strong>NetCDF</strong> Dataset with Known Names . . . . . . . . . . . . . . . 2<br />

1.3 Read<strong>in</strong>g a netCDF Dataset with Unknown Names . . . . . . . . . . . . . 2<br />

1.4 Writ<strong>in</strong>g Data <strong>in</strong> an Exist<strong>in</strong>g <strong>NetCDF</strong> Dataset . . . . . . . . . . . . . . . . . 3<br />

1.5 Add<strong>in</strong>g New Dimensions, Variables, Attributes . . . . . . . . . . . . . . . . 4<br />

1.6 Error Handl<strong>in</strong>g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.7 Compil<strong>in</strong>g and L<strong>in</strong>k<strong>in</strong>g with the <strong>NetCDF</strong> Library . . . . . . . . . . . . . . 6<br />

2 Datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.1 Datasets Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.2 <strong>NetCDF</strong> Library Interface Descriptions . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.3 NF<strong>90</strong> STRERROR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.4 Get netCDF library version: NF<strong>90</strong> INQ LIBVERS . . . . . . . . . . . . 8<br />

2.5 NF<strong>90</strong> CREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

2.6 NF<strong>90</strong> OPEN. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2.7 NF<strong>90</strong> REDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

2.8 NF<strong>90</strong> ENDDEF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.9 NF<strong>90</strong> CLOSE. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

2.10 nf<strong>90</strong> Inquire Family . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

2.11 NF<strong>90</strong> SYNC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

2.12 NF<strong>90</strong> ABORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

2.13 NF<strong>90</strong> SET FILL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3 Dimensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.1 Dimensions Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.2 NF<strong>90</strong> DEF DIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.3 NF<strong>90</strong> INQ DIMID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

3.4 NF<strong>90</strong> Inquire Dimension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.5 NF<strong>90</strong> RENAME DIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

4 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

4.1 Variables Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

4.2 Language Types Correspond<strong>in</strong>g to netCDF external data types<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

4.3 Create a Variable: NF<strong>90</strong>_DEF_VAR. . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

4.4 Get a Variable ID from Its Name: NF<strong>90</strong> INQ VARID. . . . . . . . . 29<br />

4.5 Get In<strong>for</strong>mation about a Variable from Its ID:<br />

NF<strong>90</strong> Inquire Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

4.6 Writ<strong>in</strong>g Data Values: NF<strong>90</strong> PUT VAR . . . . . . . . . . . . . . . . . . . . . . 32<br />

4.7 Read<strong>in</strong>g Data Values: NF<strong>90</strong> GET VAR. . . . . . . . . . . . . . . . . . . . . . 36<br />

4.8 Read<strong>in</strong>g and Writ<strong>in</strong>g Character Str<strong>in</strong>g Values . . . . . . . . . . . . . . . . 41


ii<br />

<strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

4.9 Fill Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42<br />

4.10 NF<strong>90</strong> RENAME VAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />

5 Attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

5.1 Attributes Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

5.2 Attribute Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

5.3 Create an Attribute: NF<strong>90</strong> PUT ATT . . . . . . . . . . . . . . . . . . . . . . . 48<br />

5.4 Get In<strong>for</strong>mation about an Attribute: NF<strong>90</strong> Inquire Att and<br />

NF<strong>90</strong> INQ ATTNAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

5.5 Get Attribute’s Values: NF<strong>90</strong> GET ATT . . . . . . . . . . . . . . . . . . . . 51<br />

5.6 Copy Attribute from One <strong>NetCDF</strong> to Another: NF<strong>90</strong> COPY ATT<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

5.7 Rename an Attribute: NF<strong>90</strong> RENAME ATT . . . . . . . . . . . . . . . . 55<br />

5.8 NF<strong>90</strong> DEL ATT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

Appendix A Appendix A - Summary of <strong>Fortran</strong><br />

<strong>90</strong> Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

Appendix B Appendix B - FORTRAN 77 to<br />

<strong>Fortran</strong> <strong>90</strong> Transition Guide . . . . . . . . . . . . . . 63<br />

The new <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

Changes to Inquiry functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

Changes to put and get function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65


Chapter 1: Use of the <strong>NetCDF</strong> Library 1<br />

1 Use of the <strong>NetCDF</strong> Library<br />

You can use the netCDF library without know<strong>in</strong>g about all of the netCDF <strong>in</strong>terface. If you<br />

are creat<strong>in</strong>g a netCDF dataset, only a handful of rout<strong>in</strong>es are required to def<strong>in</strong>e the necessary<br />

dimensions, variables, and attributes, and to write the data to the netCDF dataset. (Even<br />

less are needed if you use the ncgen utility to create the dataset be<strong>for</strong>e runn<strong>in</strong>g a program<br />

us<strong>in</strong>g netCDF library calls to write data. See section “ncgen” <strong>in</strong> <strong>NetCDF</strong> Users Guide.)<br />

Similarly, if you are writ<strong>in</strong>g software to access data stored <strong>in</strong> a particular netCDF object,<br />

only a small subset of the netCDF library is required to open the netCDF dataset and access<br />

the data. Authors of generic applications that access arbitrary netCDF datasets need to be<br />

familiar with more of the netCDF library.<br />

In this chapter we provide templates of common sequences of netCDF calls needed <strong>for</strong><br />

common uses. For clarity we present only the names of rout<strong>in</strong>es; omit declarations and error<br />

check<strong>in</strong>g; omit the type-specific suffixes of rout<strong>in</strong>e names <strong>for</strong> variables and attributes; <strong>in</strong>dent<br />

statements that are typically <strong>in</strong>voked multiple times; and use ... to represent arbitrary<br />

sequences of other statements. Full parameter lists are described <strong>in</strong> later chapters.<br />

1.1 Creat<strong>in</strong>g a <strong>NetCDF</strong> Dataset<br />

Here is a typical sequence of netCDF calls used to create a new netCDF dataset:<br />

NF<strong>90</strong>_CREATE<br />

...<br />

NF<strong>90</strong>_DEF_DIM<br />

...<br />

NF<strong>90</strong>_DEF_VAR<br />

...<br />

NF<strong>90</strong>_PUT_ATT<br />

...<br />

NF<strong>90</strong>_ENDDEF<br />

...<br />

NF<strong>90</strong>_PUT_VAR<br />

...<br />

NF<strong>90</strong>_CLOSE<br />

! create netCDF dataset: enter def<strong>in</strong>e mode<br />

! def<strong>in</strong>e dimensions: from name and length<br />

! def<strong>in</strong>e variables: from name, type, dims<br />

! assign attribute values<br />

! end def<strong>in</strong>itions: leave def<strong>in</strong>e mode<br />

! provide values <strong>for</strong> variable<br />

! close: save new netCDF dataset<br />

Only one call is needed to create a netCDF dataset, at which po<strong>in</strong>t you will be <strong>in</strong><br />

the first of two netCDF modes. When access<strong>in</strong>g an open netCDF dataset, it is either<br />

<strong>in</strong> def<strong>in</strong>e mode or data mode. In def<strong>in</strong>e mode, you can create dimensions, variables, and<br />

new attributes, but you cannot read or write variable data. In data mode, you can access<br />

data and change exist<strong>in</strong>g attributes, but you are not permitted to create new dimensions,<br />

variables, or attributes.<br />

One call to NF<strong>90</strong> DEF DIM is needed <strong>for</strong> each dimension created. Similarly, one call<br />

to NF<strong>90</strong> DEF VAR is needed <strong>for</strong> each variable creation, and one call to a member of the<br />

NF<strong>90</strong> PUT ATT family is needed <strong>for</strong> each attribute def<strong>in</strong>ed and assigned a value. To leave<br />

def<strong>in</strong>e mode and enter data mode, call NF<strong>90</strong> ENDDEF.<br />

Once <strong>in</strong> data mode, you can add new data to variables, change old values, and change<br />

values of exist<strong>in</strong>g attributes (so long as the attribute changes do not require more storage<br />

space). Data of all types is written to a netCDF variable us<strong>in</strong>g the NF<strong>90</strong> PUT VAR


2 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

subrout<strong>in</strong>e. S<strong>in</strong>gle values, arrays, or array sections may be supplied to NF<strong>90</strong> PUT VAR;<br />

optional arguments allow the writ<strong>in</strong>g of subsampled or mapped portions of the variable.<br />

(Subsampled and mapped access are general <strong>for</strong>ms of data access that are expla<strong>in</strong>ed later.)<br />

F<strong>in</strong>ally, you should explicitly close all netCDF datasets that have been opened <strong>for</strong> writ<strong>in</strong>g<br />

by call<strong>in</strong>g NF<strong>90</strong> CLOSE. By default, access to the file system is buffered by the netCDF<br />

library. If a program term<strong>in</strong>ates abnormally with netCDF datasets open <strong>for</strong> writ<strong>in</strong>g, your<br />

most recent modifications may be lost. This default buffer<strong>in</strong>g of data is disabled by sett<strong>in</strong>g<br />

the NF<strong>90</strong> SHARE flag when open<strong>in</strong>g the dataset. But even if this flag is set, changes to<br />

attribute values or changes made <strong>in</strong> def<strong>in</strong>e mode are not written out until NF<strong>90</strong> SYNC or<br />

NF<strong>90</strong> CLOSE is called.<br />

1.2 Read<strong>in</strong>g a <strong>NetCDF</strong> Dataset with Known Names<br />

Here we consider the case where you know the names of not only the netCDF datasets, but<br />

also the names of their dimensions, variables, and attributes. (Otherwise you would have<br />

to do "<strong>in</strong>quire" calls.) The order of typical C calls to read data from those variables <strong>in</strong> a<br />

netCDF dataset is:<br />

NF<strong>90</strong>_OPEN<br />

...<br />

NF<strong>90</strong>_INQ_DIMID<br />

...<br />

NF<strong>90</strong>_INQ_VARID<br />

...<br />

NF<strong>90</strong>_GET_ATT<br />

...<br />

NF<strong>90</strong>_GET_VAR<br />

...<br />

NF<strong>90</strong>_CLOSE<br />

! open exist<strong>in</strong>g netCDF dataset<br />

! get dimension IDs<br />

! get variable IDs<br />

! get attribute values<br />

! get values of variables<br />

! close netCDF dataset<br />

First, a s<strong>in</strong>gle call opens the netCDF dataset, given the dataset name, and returns a<br />

netCDF ID that is used to refer to the open netCDF dataset <strong>in</strong> all subsequent calls.<br />

Next, a call to NF<strong>90</strong> INQ DIMID <strong>for</strong> each dimension of <strong>in</strong>terest gets the dimension ID<br />

from the dimension name. Similarly, each required variable ID is determ<strong>in</strong>ed from its name<br />

by a call to NF<strong>90</strong> INQ VARID. Once variable IDs are known, variable attribute values<br />

can be retrieved us<strong>in</strong>g the netCDF ID, the variable ID, and the desired attribute name as<br />

<strong>in</strong>put to NF<strong>90</strong> GET ATT <strong>for</strong> each desired attribute. Variable data values can be directly<br />

accessed from the netCDF dataset with calls to NF<strong>90</strong> GET VAR.<br />

F<strong>in</strong>ally, the netCDF dataset is closed with NF<strong>90</strong> CLOSE. There is no need to close a<br />

dataset open only <strong>for</strong> read<strong>in</strong>g.<br />

1.3 Read<strong>in</strong>g a netCDF Dataset with Unknown Names<br />

It is possible to write programs (e.g., generic software) which do such th<strong>in</strong>gs as process<strong>in</strong>g<br />

every variable, without need<strong>in</strong>g to know <strong>in</strong> advance the names of these variables. Similarly,<br />

the names of dimensions and attributes may be unknown.<br />

Names and other <strong>in</strong><strong>for</strong>mation about netCDF objects may be obta<strong>in</strong>ed from netCDF<br />

datasets by call<strong>in</strong>g <strong>in</strong>quire functions. These return <strong>in</strong><strong>for</strong>mation about a whole netCDF


Chapter 1: Use of the <strong>NetCDF</strong> Library 3<br />

dataset, a dimension, a variable, or an attribute. The follow<strong>in</strong>g template illustrates how<br />

they are used:<br />

NF<strong>90</strong>_OPEN<br />

! open exist<strong>in</strong>g netCDF dataset<br />

...<br />

NF<strong>90</strong>_Inquire<br />

! f<strong>in</strong>d out what is <strong>in</strong> it<br />

...<br />

NF<strong>90</strong>_Inquire_Dimension ! get dimension names, lengths<br />

...<br />

NF<strong>90</strong>_Inquire_Variable ! get variable names, types, shapes<br />

...<br />

NF<strong>90</strong>_INQ_ATTNAME ! get attribute names<br />

...<br />

NF<strong>90</strong>_Inquire_Attribute ! get attribute values<br />

...<br />

NF<strong>90</strong>_GET_ATT ! get attribute values<br />

...<br />

NF<strong>90</strong>_GET_VAR<br />

! get values of variables<br />

...<br />

NF<strong>90</strong>_CLOSE<br />

! close netCDF dataset<br />

As <strong>in</strong> the previous example, a s<strong>in</strong>gle call opens the exist<strong>in</strong>g netCDF dataset, return<strong>in</strong>g<br />

a netCDF ID. This netCDF ID is given to the NF<strong>90</strong> Inquire rout<strong>in</strong>e, which returns the<br />

number of dimensions, the number of variables, the number of global attributes, and the<br />

ID of the unlimited dimension, if there is one.<br />

All the <strong>in</strong>quire functions are <strong>in</strong>expensive to use and require no I/O, s<strong>in</strong>ce the <strong>in</strong><strong>for</strong>mation<br />

they provide is stored <strong>in</strong> memory when a netCDF dataset is first opened.<br />

Dimension IDs use consecutive <strong>in</strong>tegers, beg<strong>in</strong>n<strong>in</strong>g at 1. Also dimensions, once created,<br />

cannot be deleted. There<strong>for</strong>e, know<strong>in</strong>g the number of dimension IDs <strong>in</strong> a netCDF dataset<br />

means know<strong>in</strong>g all the dimension IDs: they are the <strong>in</strong>tegers 1, 2, 3, ...up to the number of<br />

dimensions. For each dimension ID, a call to the <strong>in</strong>quire function NF<strong>90</strong> Inquire Dimension<br />

returns the dimension name and length.<br />

Variable IDs are also assigned from consecutive <strong>in</strong>tegers 1, 2, 3, ... up to the number of<br />

variables. These can be used <strong>in</strong> NF<strong>90</strong> Inquire Variable calls to f<strong>in</strong>d out the names, types,<br />

shapes, and the number of attributes assigned to each variable.<br />

Once the number of attributes <strong>for</strong> a variable is known, successive calls to<br />

NF<strong>90</strong> INQ ATTNAME return the name <strong>for</strong> each attribute given the netCDF ID, variable<br />

ID, and attribute number. Armed with the attribute name, a call to NF<strong>90</strong> Inquire Variable<br />

returns its type and length. Given the type and length, you can allocate enough space to<br />

hold the attribute values. Then a call to NF<strong>90</strong> GET ATT returns the attribute values.<br />

Once the IDs and shapes of netCDF variables are known, data values can be accessed<br />

by call<strong>in</strong>g NF<strong>90</strong> GET VAR.<br />

1.4 Writ<strong>in</strong>g Data <strong>in</strong> an Exist<strong>in</strong>g <strong>NetCDF</strong> Dataset<br />

With write access to an exist<strong>in</strong>g netCDF dataset, you can overwrite data values <strong>in</strong> exist<strong>in</strong>g<br />

variables or append more data to record variables along the unlimited (record) dimension.


4 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

To append more data to non-record variables requires chang<strong>in</strong>g the shape of such variables,<br />

which means creat<strong>in</strong>g a new netCDF dataset, def<strong>in</strong><strong>in</strong>g new variables with the desired<br />

shape, and copy<strong>in</strong>g data. The netCDF data model was not designed to make such "schema<br />

changes" efficient or easy, so it is best to specify the shapes of variables correctly when you<br />

create a netCDF dataset, and to anticipate which variables will later grow by us<strong>in</strong>g the<br />

unlimited dimension <strong>in</strong> their def<strong>in</strong>ition.<br />

The follow<strong>in</strong>g code template lists a typical sequence of calls to overwrite some exist<strong>in</strong>g<br />

values and add some new records to record variables <strong>in</strong> an exist<strong>in</strong>g netCDF dataset with<br />

known variable names:<br />

NF<strong>90</strong>_OPEN<br />

...<br />

NF<strong>90</strong>_INQ_VARID<br />

...<br />

NF<strong>90</strong>_PUT_VAR<br />

...<br />

NF<strong>90</strong>_PUT_ATT<br />

...<br />

NF<strong>90</strong>_CLOSE<br />

! open exist<strong>in</strong>g netCDF dataset<br />

! get variable IDs<br />

! provide new values <strong>for</strong> variables, if any<br />

! provide new values <strong>for</strong> attributes, if any<br />

! close netCDF dataset<br />

A netCDF dataset is first opened by the NF<strong>90</strong> OPEN call. This call puts the open<br />

dataset <strong>in</strong> data mode, which means exist<strong>in</strong>g data values can be accessed and changed,<br />

exist<strong>in</strong>g attributes can be changed, but no new dimensions, variables, or attributes can be<br />

added.<br />

Next, calls to NF<strong>90</strong> INQ VARID get the variable ID from the name, <strong>for</strong> each variable<br />

you want to write. Then each call to NF<strong>90</strong> PUT VAR writes data <strong>in</strong>to a specified variable,<br />

either a s<strong>in</strong>gle value at a time, or a whole set of values at a time, depend<strong>in</strong>g on which<br />

variant of the <strong>in</strong>terface is used. The calls used to overwrite values of non-record variables<br />

are the same as are used to overwrite values of record variables or append new data to record<br />

variables. The difference is that, with record variables, the record dimension is extended by<br />

writ<strong>in</strong>g values that don’t yet exist <strong>in</strong> the dataset. This extends all record variables at once,<br />

writ<strong>in</strong>g "fill values" <strong>for</strong> record variables <strong>for</strong> which the data has not yet been written (but<br />

see Section 4.9 [Fill Values], page 42 to specify different behavior).<br />

Calls to NF<strong>90</strong> PUT ATT may be used to change the values of exist<strong>in</strong>g attributes, although<br />

data that changes after a file is created is typically stored <strong>in</strong> variables rather than<br />

attributes.<br />

F<strong>in</strong>ally, you should explicitly close any netCDF datasets <strong>in</strong>to which data has been written<br />

by call<strong>in</strong>g NF<strong>90</strong> CLOSE be<strong>for</strong>e program term<strong>in</strong>ation. Otherwise, modifications to the<br />

dataset may be lost.<br />

1.5 Add<strong>in</strong>g New Dimensions, Variables, Attributes<br />

An exist<strong>in</strong>g netCDF dataset can be extensively altered. New dimensions, variables, and<br />

attributes can be added or exist<strong>in</strong>g ones renamed, and exist<strong>in</strong>g attributes can be deleted.<br />

Exist<strong>in</strong>g dimensions, variables, and attributes can be renamed. The follow<strong>in</strong>g code template<br />

lists a typical sequence of calls to add new netCDF components to an exist<strong>in</strong>g dataset:<br />

NF<strong>90</strong>_OPEN<br />

...<br />

! open exist<strong>in</strong>g netCDF dataset


Chapter 1: Use of the <strong>NetCDF</strong> Library 5<br />

NF<strong>90</strong>_REDEF<br />

...<br />

NF<strong>90</strong>_DEF_DIM<br />

...<br />

NF<strong>90</strong>_DEF_VAR<br />

...<br />

NF<strong>90</strong>_PUT_ATT<br />

...<br />

NF<strong>90</strong>_ENDDEF<br />

...<br />

NF<strong>90</strong>_PUT_VAR<br />

...<br />

NF<strong>90</strong>_CLOSE<br />

! put it <strong>in</strong>to def<strong>in</strong>e mode<br />

! def<strong>in</strong>e additional dimensions (if any)<br />

! def<strong>in</strong>e additional variables (if any)<br />

! def<strong>in</strong>e other attributes (if any)<br />

! check def<strong>in</strong>itions, leave def<strong>in</strong>e mode<br />

! provide new variable values<br />

! close netCDF dataset<br />

A netCDF dataset is first opened by the NF<strong>90</strong> OPEN call. This call puts the open<br />

dataset <strong>in</strong> data mode, which means exist<strong>in</strong>g data values can be accessed and changed,<br />

exist<strong>in</strong>g attributes can be changed (so long as they do not grow), but noth<strong>in</strong>g can be added.<br />

To add new netCDF dimensions, variables, or attributes you must enter def<strong>in</strong>e mode, by<br />

call<strong>in</strong>g NF<strong>90</strong> REDEF. In def<strong>in</strong>e mode, call NF<strong>90</strong> DEF DIM to def<strong>in</strong>e new dimensions,<br />

NF<strong>90</strong> DEF VAR to def<strong>in</strong>e new variables, and NF<strong>90</strong> PUT ATT to assign new attributes to<br />

variables or enlarge old attributes.<br />

You can leave def<strong>in</strong>e mode and reenter data mode, check<strong>in</strong>g all the new def<strong>in</strong>itions <strong>for</strong><br />

consistency and committ<strong>in</strong>g the changes to disk, by call<strong>in</strong>g NF<strong>90</strong> ENDDEF. If you do not<br />

wish to reenter data mode, just call NF<strong>90</strong> CLOSE, which will have the effect of first call<strong>in</strong>g<br />

NF<strong>90</strong> ENDDEF.<br />

Until the NF<strong>90</strong> ENDDEF call, you may back out of all the redef<strong>in</strong>itions made <strong>in</strong> def<strong>in</strong>e<br />

mode and restore the previous state of the netCDF dataset by call<strong>in</strong>g NF<strong>90</strong> ABORT. You<br />

may also use the NF<strong>90</strong> ABORT call to restore the netCDF dataset to a consistent state<br />

if the call to NF<strong>90</strong> ENDDEF fails. If you have called NF<strong>90</strong> CLOSE from def<strong>in</strong>ition mode<br />

and the implied call to NF<strong>90</strong> ENDDEF fails, NF<strong>90</strong> ABORT will automatically be called to<br />

close the netCDF dataset and leave it <strong>in</strong> its previous consistent state (be<strong>for</strong>e you entered<br />

def<strong>in</strong>e mode).<br />

At most one process should have a netCDF dataset open <strong>for</strong> writ<strong>in</strong>g at one time. The<br />

library is designed to provide limited support <strong>for</strong> multiple concurrent readers with one<br />

writer, via discipl<strong>in</strong>ed use of the NF<strong>90</strong> SYNC function and the NF<strong>90</strong> SHARE flag. If a<br />

writer makes changes <strong>in</strong> def<strong>in</strong>e mode, such as the addition of new variables, dimensions, or<br />

attributes, some means external to the library is necessary to prevent readers from mak<strong>in</strong>g<br />

concurrent accesses and to <strong>in</strong><strong>for</strong>m readers to call NF<strong>90</strong> SYNC be<strong>for</strong>e the next access.<br />

1.6 Error Handl<strong>in</strong>g<br />

The netCDF library provides the facilities needed to handle errors <strong>in</strong> a flexible way. Each<br />

netCDF function returns an <strong>in</strong>teger status value. If the returned status value <strong>in</strong>dicates an<br />

error, you may handle it <strong>in</strong> any way desired, from pr<strong>in</strong>t<strong>in</strong>g an associated error message and<br />

exit<strong>in</strong>g to ignor<strong>in</strong>g the error <strong>in</strong>dication and proceed<strong>in</strong>g (not recommended!). For simplicity,<br />

the examples <strong>in</strong> this guide check the error status and call a separate function to handle any<br />

errors.


6 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

The NF<strong>90</strong> STRERROR function is available to convert a returned <strong>in</strong>teger error status<br />

<strong>in</strong>to an error message str<strong>in</strong>g.<br />

Occasionally, low-level I/O errors may occur <strong>in</strong> a layer below the netCDF library. For<br />

example, if a write operation causes you to exceed disk quotas or to attempt to write to<br />

a device that is no longer available, you may get an error from a layer below the netCDF<br />

library, but the result<strong>in</strong>g write error will still be reflected <strong>in</strong> the returned status value.<br />

1.7 Compil<strong>in</strong>g and L<strong>in</strong>k<strong>in</strong>g with the <strong>NetCDF</strong> Library<br />

Details of how to compile and l<strong>in</strong>k a program that uses the netCDF C or FORTRAN<br />

<strong>in</strong>terfaces differ, depend<strong>in</strong>g on the operat<strong>in</strong>g system, the available compilers, and where the<br />

netCDF library and <strong>in</strong>clude files are <strong>in</strong>stalled. Nevertheless, we provide here examples of<br />

how to compile and l<strong>in</strong>k a program that uses the netCDF library on a Unix plat<strong>for</strong>m, so<br />

that you can adjust these examples to fit your <strong>in</strong>stallation.<br />

Every <strong>Fortran</strong> <strong>90</strong> procedure or module which references netCDF constants or procedures<br />

must have access to the module <strong>in</strong><strong>for</strong>mation created when the netCDF module was compiled.<br />

The suffix <strong>for</strong> this file depends on the compiler, but is often .MOD. Most <strong>Fortran</strong> <strong>90</strong><br />

compilers do not allow you to specify an alternative location <strong>for</strong> this file as you might the<br />

location of external libraries. The simplest solution, there<strong>for</strong>e, is to create a symbolic l<strong>in</strong>k<br />

from the directory <strong>in</strong> which your code resides to the location of the pre-compiled netCDF<br />

module. For example:<br />

ln -s /usr/local/netcdf/src/f<strong>90</strong>/netcdf.mod .<br />

You may then compile source files which reference netCDF constants or procedures.<br />

f<strong>90</strong> -c mymodule.f<strong>90</strong><br />

Unless the netCDF library is <strong>in</strong>stalled <strong>in</strong> a standard directory where the l<strong>in</strong>ker always<br />

looks, you must use the -L and -l options to l<strong>in</strong>k an object file that uses the netCDF library.<br />

For example:<br />

f<strong>90</strong> -o myprogram myprogram.o -L/usr/local/netcdf/lib -lnetcdf


Chapter 2: Datasets 7<br />

2 Datasets<br />

2.1 Datasets Introduction<br />

This chapter presents the <strong>in</strong>terfaces of the netCDF functions that deal with a netCDF<br />

dataset or the whole netCDF library.<br />

A netCDF dataset that has not yet been opened can only be referred to by its dataset<br />

name. Once a netCDF dataset is opened, it is referred to by a netCDF ID, which is a small<br />

nonnegative <strong>in</strong>teger returned when you create or open the dataset. A netCDF ID is much<br />

like a file descriptor <strong>in</strong> C or a logical unit number <strong>in</strong> FORTRAN. In any s<strong>in</strong>gle program,<br />

the netCDF IDs of dist<strong>in</strong>ct open netCDF datasets are dist<strong>in</strong>ct. A s<strong>in</strong>gle netCDF dataset<br />

may be opened multiple times and will then have multiple dist<strong>in</strong>ct netCDF IDs; however<br />

at most one of the open <strong>in</strong>stances of a s<strong>in</strong>gle netCDF dataset should permit writ<strong>in</strong>g. When<br />

an open netCDF dataset is closed, the ID is no longer associated with a netCDF dataset.<br />

Functions that deal with the netCDF library <strong>in</strong>clude:<br />

• Get version of library.<br />

• Get error message correspond<strong>in</strong>g to a returned error code.<br />

The operations supported on a netCDF dataset as a s<strong>in</strong>gle object are:<br />

• Create, given dataset name and whether to overwrite or not.<br />

• Open <strong>for</strong> access, given dataset name and read or write <strong>in</strong>tent.<br />

• Put <strong>in</strong>to def<strong>in</strong>e mode, to add dimensions, variables, or attributes.<br />

• Take out of def<strong>in</strong>e mode, check<strong>in</strong>g consistency of additions.<br />

• Close, writ<strong>in</strong>g to disk if required.<br />

• Inquire about the number of dimensions, number of variables, number of global attributes,<br />

and ID of the unlimited dimension, if any.<br />

• Synchronize to disk to make sure it is current.<br />

• Set and unset nofill mode <strong>for</strong> optimized sequential writes.<br />

• After a summary of conventions used <strong>in</strong> describ<strong>in</strong>g the netCDF <strong>in</strong>terfaces, the rest of<br />

this chapter presents a detailed description of the <strong>in</strong>terfaces <strong>for</strong> these operations.<br />

2.2 <strong>NetCDF</strong> Library Interface Descriptions<br />

Each <strong>in</strong>terface description <strong>for</strong> a particular netCDF function <strong>in</strong> this and later chapters conta<strong>in</strong>s:<br />

• a description of the purpose of the function;<br />

• a <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface block that presents the type and order of the <strong>for</strong>mal parameters<br />

to the function;<br />

• a description of each <strong>for</strong>mal parameter <strong>in</strong> the C <strong>in</strong>terface;<br />

• a list of possible error conditions; and<br />

• an example of a <strong>Fortran</strong> <strong>90</strong> program fragment call<strong>in</strong>g the netCDF function (and perhaps<br />

other netCDF functions).


8 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

The examples follow a simple convention <strong>for</strong> error handl<strong>in</strong>g, always check<strong>in</strong>g the error<br />

status returned from each netCDF function call and call<strong>in</strong>g a handle error function <strong>in</strong> case<br />

an error was detected. For an example of such a function, see Section 5.2 "Get error message<br />

correspond<strong>in</strong>g to error status: nc strerror".<br />

2.3 NF<strong>90</strong> STRERROR<br />

The function NF<strong>90</strong> STRERROR returns a static reference to an error message str<strong>in</strong>g correspond<strong>in</strong>g<br />

to an <strong>in</strong>teger netCDF error status or to a system error number, presumably<br />

returned by a previous call to some other netCDF function. The list of netCDF error<br />

status codes is available <strong>in</strong> the appropriate <strong>in</strong>clude file <strong>for</strong> each language b<strong>in</strong>d<strong>in</strong>g.<br />

Usage<br />

NCERR<br />

Errors<br />

function nf<strong>90</strong>_strerror(ncerr)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncerr<br />

character(len = 80) :: nf<strong>90</strong>_strerror<br />

An error status that might have been returned from a previous call to some<br />

netCDF function.<br />

If you provide an <strong>in</strong>valid <strong>in</strong>teger error status that does not correspond to any netCDF error<br />

message or or to any system error message (as understood by the system strerror function),<br />

NF<strong>90</strong> STRERROR returns a str<strong>in</strong>g <strong>in</strong>dicat<strong>in</strong>g that there is no such error status.<br />

Example<br />

Here is an example of a simple error handl<strong>in</strong>g function that uses NF<strong>90</strong> STRERROR to pr<strong>in</strong>t<br />

the error message correspond<strong>in</strong>g to the netCDF error status returned from any netCDF<br />

function call and then exit:<br />

subrout<strong>in</strong>e handle_err(status)<br />

<strong>in</strong>teger, <strong>in</strong>tent ( <strong>in</strong>) :: status<br />

if(status /= nf<strong>90</strong>_noerr) then<br />

pr<strong>in</strong>t *, trim(nf<strong>90</strong>_strerror(status))<br />

stop "Stopped"<br />

end if<br />

end subrout<strong>in</strong>e handle_err<br />

2.4 Get netCDF library version: NF<strong>90</strong> INQ LIBVERS<br />

The function NF<strong>90</strong> INQ LIBVERS returns a str<strong>in</strong>g identify<strong>in</strong>g the version of the netCDF<br />

library, and when it was built.<br />

Usage<br />

function nf<strong>90</strong>_<strong>in</strong>q_libvers()<br />

character(len = 80) :: nf<strong>90</strong>_<strong>in</strong>q_libvers


Chapter 2: Datasets 9<br />

Errors<br />

This function takes no arguments, and returns no error status.<br />

Example<br />

Here is an example us<strong>in</strong>g nc <strong>in</strong>q libvers to pr<strong>in</strong>t the version of the netCDF library with<br />

which the program is l<strong>in</strong>ked:<br />

pr<strong>in</strong>t *, trim(nf<strong>90</strong>_<strong>in</strong>q_libvers())<br />

2.5 NF<strong>90</strong> CREATE<br />

This function creates a new netCDF dataset, return<strong>in</strong>g a netCDF ID that can subsequently<br />

be used to refer to the netCDF dataset <strong>in</strong> other netCDF function calls. The new netCDF<br />

dataset opened <strong>for</strong> write access and placed <strong>in</strong> def<strong>in</strong>e mode, ready <strong>for</strong> you to add dimensions,<br />

variables, and attributes.<br />

A creation mode flag specifies whether to overwrite any exist<strong>in</strong>g dataset with the same<br />

name and whether access to the dataset is shared.<br />

Usage<br />

path<br />

function nf<strong>90</strong>_create(path, cmode, ncid)<br />

character (len = *), <strong>in</strong>tent(<strong>in</strong> ) :: path<br />

<strong>in</strong>teger, <strong>in</strong>tent(<strong>in</strong> ) :: cmode<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong> ) :: <strong>in</strong>itialsize<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong>out) :: chunksize<br />

<strong>in</strong>teger, <strong>in</strong>tent( out) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_create<br />

The file name of the new netCDF dataset.<br />

cmode The creation mode flag. The follow<strong>in</strong>g flags are available:<br />

NF<strong>90</strong> NOCLOBBER, NF<strong>90</strong> SHARE, and NF<strong>90</strong> 64BIT OFFSET.<br />

Sett<strong>in</strong>g NF<strong>90</strong> NOCLOBBER means you do not want to clobber (overwrite) an<br />

exist<strong>in</strong>g dataset; an error (NF<strong>90</strong> EEXIST) is returned if the specified dataset<br />

already exists.<br />

The NF<strong>90</strong> SHARE flag is appropriate when one process may be writ<strong>in</strong>g the<br />

dataset and one or more other processes read<strong>in</strong>g the dataset concurrently; it<br />

means that dataset accesses are not buffered and cach<strong>in</strong>g is limited. S<strong>in</strong>ce<br />

the buffer<strong>in</strong>g scheme is optimized <strong>for</strong> sequential access, programs that do not<br />

access data sequentially may see some per<strong>for</strong>mance improvement by sett<strong>in</strong>g the<br />

NF<strong>90</strong> SHARE flag.<br />

Sett<strong>in</strong>g NF<strong>90</strong> 64BIT OFFSET causes netCDF to create a 64-bit offset <strong>for</strong>mat<br />

file, <strong>in</strong>stead of a netCDF classic <strong>for</strong>mat file. The 64-bit offset <strong>for</strong>mat imposes far<br />

fewer restrictions on very large (i.e. over 2 GB) data files. See section “Large<br />

File Support” <strong>in</strong> <strong>NetCDF</strong> Users’ Guide.<br />

A zero value (def<strong>in</strong>ed <strong>for</strong> convenience as NF<strong>90</strong> CLOBBER) specifies the default<br />

behavior: overwrite any exist<strong>in</strong>g dataset with the same file name and buffer and


10 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

cache accesses <strong>for</strong> efficiency. The dataset will be <strong>in</strong> netCDF classic <strong>for</strong>mat. See<br />

section “<strong>NetCDF</strong> Classic Format Limitations” <strong>in</strong> <strong>NetCDF</strong> Users’ Guide.<br />

ncid<br />

Returned netCDF ID.<br />

The follow<strong>in</strong>g optional arguments allow additional per<strong>for</strong>mance tun<strong>in</strong>g.<br />

<strong>in</strong>itialsize<br />

The <strong>in</strong>itial size of the file (<strong>in</strong> bytes) at creation time. A value of 0 causes the<br />

file size to be computed when nf<strong>90</strong> enddef is called.<br />

chunksize<br />

Controls a space versus time trade-off, memory allocated <strong>in</strong> the netcdf library<br />

versus number of system calls. Because of <strong>in</strong>ternal requirements, the value may<br />

not be set to exactly the value requested. The actual value chosen is returned.<br />

The library chooses a system-dependent default value if NF<strong>90</strong> SIZEHINT DEFAULT<br />

is supplied as <strong>in</strong>put. If the "preferred I/O block size" is available from the<br />

stat() system call as member st blksize this value is used. Lack<strong>in</strong>g that, twice<br />

the system pagesize is used. Lack<strong>in</strong>g a call to discover the system pagesize,<br />

the default chunksize is set to 8192 bytes.<br />

The chunksize is a property of a given open netcdf descriptor ncid, it is not a<br />

persistent property of the netcdf dataset.<br />

Errors<br />

NF<strong>90</strong> CREATE returns the value NF<strong>90</strong> NOERR if no errors occurred. Possible causes of<br />

errors <strong>in</strong>clude:<br />

• Pass<strong>in</strong>g a dataset name that <strong>in</strong>cludes a directory that does not exist.<br />

• Specify<strong>in</strong>g a dataset name of a file that exists and also specify<strong>in</strong>g NF<strong>90</strong> NOCLOBBER.<br />

• Specify<strong>in</strong>g a mean<strong>in</strong>gless value <strong>for</strong> the creation mode.<br />

• Attempt<strong>in</strong>g to create a netCDF dataset <strong>in</strong> a directory where you don’t have permission<br />

to create files.<br />

Example<br />

In this example we create a netCDF dataset named foo.nc; we want the dataset to be<br />

created <strong>in</strong> the current directory only if a dataset with that name does not already exist:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_create(path = "foo.nc", cmode = nf<strong>90</strong>_noclobber, ncid = ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

2.6 NF<strong>90</strong> OPEN<br />

The function NF<strong>90</strong> OPEN opens an exist<strong>in</strong>g netCDF dataset <strong>for</strong> access.


Chapter 2: Datasets 11<br />

Usage<br />

function nf<strong>90</strong>_open(path, mode, ncid, chunksize)<br />

character (len = *), <strong>in</strong>tent(<strong>in</strong> ) :: path<br />

<strong>in</strong>teger, <strong>in</strong>tent(<strong>in</strong> ) :: mode<br />

<strong>in</strong>teger, <strong>in</strong>tent( out) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong>out) :: chunksize<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_open<br />

path<br />

omode<br />

ncid<br />

File name <strong>for</strong> netCDF dataset to be opened.<br />

A zero value (or NF<strong>90</strong> NOWRITE) specifies the default behavior: open the<br />

dataset with read-only access, buffer<strong>in</strong>g and cach<strong>in</strong>g accesses <strong>for</strong> efficiency<br />

Otherwise, the creation mode is NF<strong>90</strong> WRITE, NF<strong>90</strong> SHARE, or<br />

NF<strong>90</strong> WRITE|NF<strong>90</strong> SHARE. Sett<strong>in</strong>g the NF<strong>90</strong> WRITE flag opens the<br />

dataset with read-write access. ("Writ<strong>in</strong>g" means any k<strong>in</strong>d of change to the<br />

dataset, <strong>in</strong>clud<strong>in</strong>g append<strong>in</strong>g or chang<strong>in</strong>g data, add<strong>in</strong>g or renam<strong>in</strong>g dimensions,<br />

variables, and attributes, or delet<strong>in</strong>g attributes.) The NF<strong>90</strong> SHARE flag<br />

is appropriate when one process may be writ<strong>in</strong>g the dataset and one or<br />

more other processes read<strong>in</strong>g the dataset concurrently; it means that dataset<br />

accesses are not buffered and cach<strong>in</strong>g is limited. S<strong>in</strong>ce the buffer<strong>in</strong>g scheme is<br />

optimized <strong>for</strong> sequential access, programs that do not access data sequentially<br />

may see some per<strong>for</strong>mance improvement by sett<strong>in</strong>g the NF<strong>90</strong> SHARE flag.<br />

Returned netCDF ID.<br />

The follow<strong>in</strong>g optional argument allows additional per<strong>for</strong>mance tun<strong>in</strong>g.<br />

chunksize<br />

Controls a space versus time trade-off, memory allocated <strong>in</strong> the netcdf library<br />

versus number of system calls. Because of <strong>in</strong>ternal requirements, the value may<br />

not be set to exactly the value requested. The actual value chosen is returned.<br />

The library chooses a system-dependent default value if NF<strong>90</strong> SIZEHINT DEFAULT<br />

is supplied as <strong>in</strong>put. If the "preferred I/O block size" is available from the<br />

stat() system call as member st blksize this value is used. Lack<strong>in</strong>g that, twice<br />

the system pagesize is used. Lack<strong>in</strong>g a call to discover the system pagesize,<br />

the default chunksize is set to 8192 bytes.<br />

The chunksize is a property of a given open netcdf descriptor ncid, it is not a<br />

persistent property of the netcdf dataset.<br />

Errors<br />

Otherwise, the re-<br />

NF<strong>90</strong> OPEN returns the value NF<strong>90</strong> NOERR if no errors occurred.<br />

turned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified netCDF dataset does not exist.<br />

• A mean<strong>in</strong>gless mode was specified.


12 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> OPEN to open an exist<strong>in</strong>g netCDF dataset named foo.nc<br />

<strong>for</strong> read-only, non-shared access:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_open(path = "foo.nc", cmode = nf<strong>90</strong>_nowrite, ncid = ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

2.7 NF<strong>90</strong> REDEF<br />

The function NF<strong>90</strong> REDEF puts an open netCDF dataset <strong>in</strong>to def<strong>in</strong>e mode, so dimensions,<br />

variables, and attributes can be added or renamed and attributes can be deleted.<br />

Usage<br />

function nf<strong>90</strong>_redef(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_redef<br />

ncid<br />

netCDF ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Errors<br />

NF<strong>90</strong> REDEF returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the returned<br />

status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified netCDF dataset is already <strong>in</strong> def<strong>in</strong>e mode.<br />

• The specified netCDF dataset was opened <strong>for</strong> read-only.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> REDEF to open an exist<strong>in</strong>g netCDF dataset named foo.nc<br />

and put it <strong>in</strong>to def<strong>in</strong>e mode:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid) ! Open dataset<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_redef(ncid)<br />

! Put the file <strong>in</strong> def<strong>in</strong>e mode<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)


Chapter 2: Datasets 13<br />

2.8 NF<strong>90</strong> ENDDEF<br />

The function NF<strong>90</strong> ENDDEF takes an open netCDF dataset out of def<strong>in</strong>e mode. The<br />

changes made to the netCDF dataset while it was <strong>in</strong> def<strong>in</strong>e mode are checked and committed<br />

to disk if no problems occurred. Non-record variables may be <strong>in</strong>itialized to a "fill value" as<br />

well (see Section 2.13 [NF<strong>90</strong> SET FILL], page 19). The netCDF dataset is then placed <strong>in</strong><br />

data mode, so variable data can be read or written.<br />

This call may <strong>in</strong>volve copy<strong>in</strong>g data under some circumstances. For a more extensive<br />

discussion See section “File Structure and Per<strong>for</strong>mance” <strong>in</strong> <strong>NetCDF</strong> Users Guide.<br />

Usage<br />

ncid<br />

function nf<strong>90</strong>_enddef(ncid, h_m<strong>in</strong>free, v_align, v_m<strong>in</strong>free, r_align)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent( <strong>in</strong>) :: h_m<strong>in</strong>free, v_align, v_m<strong>in</strong>free, r_align<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_enddef<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

The follow<strong>in</strong>g arguments allow additional per<strong>for</strong>mance tun<strong>in</strong>g. Note: these arguments<br />

expose <strong>in</strong>ternals of the netcdf version 1 file <strong>for</strong>mat, and may not be available <strong>in</strong> future netcdf<br />

implementations.<br />

The current netcdf file <strong>for</strong>mat has three sections: the "header" section, the data section<br />

<strong>for</strong> fixed size variables, and the data section <strong>for</strong> variables which have an unlimited dimension<br />

(record variables). The header beg<strong>in</strong>s at the beg<strong>in</strong>n<strong>in</strong>g of the file. The <strong>in</strong>dex (offset) of the<br />

beg<strong>in</strong>n<strong>in</strong>g of the other two sections is conta<strong>in</strong>ed <strong>in</strong> the header. Typically, there is no space<br />

between the sections. This causes copy<strong>in</strong>g overhead to accrue if one wishes to change the<br />

size of the sections, as may happen when chang<strong>in</strong>g the names of th<strong>in</strong>gs, text attribute values,<br />

add<strong>in</strong>g attributes or add<strong>in</strong>g variables. Also, <strong>for</strong> buffered i/o, there may be advantages to<br />

align<strong>in</strong>g sections <strong>in</strong> certa<strong>in</strong> ways.<br />

h_m<strong>in</strong>free<br />

v_m<strong>in</strong>free<br />

v_align<br />

r_align<br />

The follow<strong>in</strong>g parameters allow one to control costs of future calls to nf<strong>90</strong> redef<br />

or nf<strong>90</strong> enddef by request<strong>in</strong>g that some space be available at the end of the<br />

section. The default value <strong>for</strong> both arguments is 0.<br />

Size of the pad (<strong>in</strong> bytes) at the end of the "header" section.<br />

Size of the pad (<strong>in</strong> bytes) at the end of the data section <strong>for</strong> fixed size variables.<br />

The align parameters allow one to set the alignment of the beg<strong>in</strong>n<strong>in</strong>g of<br />

the correspond<strong>in</strong>g sections. The beg<strong>in</strong>n<strong>in</strong>g of the section is rounded up<br />

to an <strong>in</strong>dex which is a multiple of the align parameter. The flag value<br />

NF<strong>90</strong> ALIGN CHUNK tells the library to use the chunksize (see above) as<br />

the align parameter. The default value <strong>for</strong> both arguments is 4 bytes.<br />

The alignment of the beg<strong>in</strong>n<strong>in</strong>g of the data section <strong>for</strong> fixed size variables.<br />

The alignment of the beg<strong>in</strong>n<strong>in</strong>g of the data section <strong>for</strong> variables which have an<br />

unlimited dimension (record variables).


14 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Errors<br />

NF<strong>90</strong> ENDDEF returns the value NF<strong>90</strong> NOERR if no errors occurred.<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified netCDF dataset is not <strong>in</strong> def<strong>in</strong>e mode.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Otherwise, the<br />

• The size of one or more variables exceed the size constra<strong>in</strong>ts <strong>for</strong> whichever variant of<br />

the file <strong>for</strong>mat is <strong>in</strong> use). See section “Large File Support” <strong>in</strong> The <strong>NetCDF</strong> Users’<br />

Guide.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> ENDDEF to f<strong>in</strong>ish the def<strong>in</strong>itions of a new netCDF dataset<br />

named foo.nc and put it <strong>in</strong>to data mode:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_create("foo.nc", nf<strong>90</strong>_noclobber, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

... ! create dimensions, variables, attributes<br />

status = nf<strong>90</strong>_enddef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

2.9 NF<strong>90</strong> CLOSE<br />

The function NF<strong>90</strong> CLOSE closes an open netCDF dataset. If the dataset is <strong>in</strong> def<strong>in</strong>e mode,<br />

NF<strong>90</strong> ENDDEF will be called be<strong>for</strong>e clos<strong>in</strong>g. (In this case, if NF<strong>90</strong> ENDDEF returns an<br />

error, NF<strong>90</strong> ABORT will automatically be called to restore the dataset to the consistent<br />

state be<strong>for</strong>e def<strong>in</strong>e mode was last entered.) After an open netCDF dataset is closed, its<br />

netCDF ID may be reassigned to the next netCDF dataset that is opened or created.<br />

Usage<br />

function nf<strong>90</strong>_close(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_close<br />

ncid<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Errors<br />

NF<strong>90</strong> CLOSE returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the returned<br />

status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• Def<strong>in</strong>e mode was entered and the automatic call made to NF<strong>90</strong> ENDDEF failed.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.


Chapter 2: Datasets 15<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> CLOSE to f<strong>in</strong>ish the def<strong>in</strong>itions of a new netCDF dataset<br />

named foo.nc and release its netCDF ID:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_create("foo.nc", nf<strong>90</strong>_noclobber, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

... ! create dimensions, variables, attributes<br />

status = nf<strong>90</strong>_close(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

2.10 nf<strong>90</strong> Inquire Family<br />

The NF<strong>90</strong> Inquire subrout<strong>in</strong>e returns <strong>in</strong><strong>for</strong>mation about an open netCDF dataset, given<br />

its netCDF ID. The subrout<strong>in</strong>e can be called from either def<strong>in</strong>e mode or data mode, and<br />

returns values <strong>for</strong> any or all of the follow<strong>in</strong>g: the number of dimensions, the number of<br />

variables, the number of global attributes, and the dimension ID of the dimension def<strong>in</strong>ed<br />

with unlimited length, if any.<br />

No I/O is per<strong>for</strong>med when NF<strong>90</strong> Inquire is called, s<strong>in</strong>ce the required <strong>in</strong><strong>for</strong>mation is<br />

available <strong>in</strong> memory <strong>for</strong> each open netCDF dataset.<br />

Usage<br />

ncid<br />

function nf<strong>90</strong>_Inquire(ncid, nDimensions, nVariables, nAttributes, &<br />

unlimitedDimId)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(out) :: nDimensions, nVariables, &<br />

nAttributes, unlimitedDimId<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

nDimensions<br />

Returned number of dimensions def<strong>in</strong>ed <strong>for</strong> this netCDF dataset.<br />

nVariables<br />

Returned number of variables def<strong>in</strong>ed <strong>for</strong> this netCDF dataset.<br />

nAttributes<br />

Returned number of global attributes def<strong>in</strong>ed <strong>for</strong> this netCDF dataset.<br />

unlimitedDimID<br />

Returned ID of the unlimited dimension, if there is one <strong>for</strong> this netCDF dataset.<br />

If no unlimited length dimension has been def<strong>in</strong>ed, -1 is returned.<br />

Errors<br />

Function NF<strong>90</strong> Inquire returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:


16 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g nf<strong>90</strong> Inquire to f<strong>in</strong>d out about a netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, nDims, nVars, nGlobalAtts, unlimDimID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = Nf<strong>90</strong>_Inquire(ncid, nDims, nVars, nGlobalAtts, unlimdimid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = Nf<strong>90</strong>_Inquire(ncid, nDimensions = nDims, &<br />

unlimitedDimID = unlimdimid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

2.11 NF<strong>90</strong> SYNC<br />

The function NF<strong>90</strong> SYNC offers a way to synchronize the disk copy of a netCDF dataset<br />

with <strong>in</strong>-memory buffers. There are two reasons you might want to synchronize after writes:<br />

• To m<strong>in</strong>imize data loss <strong>in</strong> case of abnormal term<strong>in</strong>ation, or<br />

• To make data available to other processes <strong>for</strong> read<strong>in</strong>g immediately after it is written.<br />

But note that a process that already had the dataset open <strong>for</strong> read<strong>in</strong>g would not see the<br />

number of records <strong>in</strong>crease when the writ<strong>in</strong>g process calls NF<strong>90</strong> SYNC; to accomplish<br />

this, the read<strong>in</strong>g process must call NF<strong>90</strong> SYNC.<br />

This function is backward-compatible with previous versions of the netCDF library. The<br />

<strong>in</strong>tent was to allow shar<strong>in</strong>g of a netCDF dataset among multiple readers and one writer, by<br />

hav<strong>in</strong>g the writer call NF<strong>90</strong> SYNC after writ<strong>in</strong>g and the readers call NF<strong>90</strong> SYNC be<strong>for</strong>e<br />

each read. For a writer, this flushes buffers to disk. For a reader, it makes sure that the<br />

next read will be from disk rather than from previously cached buffers, so that the reader<br />

will see changes made by the writ<strong>in</strong>g process (e.g., the number of records written) without<br />

hav<strong>in</strong>g to close and reopen the dataset. If you are only access<strong>in</strong>g a small amount of data,<br />

it can be expensive <strong>in</strong> computer resources to always synchronize to disk after every write,<br />

s<strong>in</strong>ce you are giv<strong>in</strong>g up the benefits of buffer<strong>in</strong>g.<br />

An easier way to accomplish shar<strong>in</strong>g (and what is now recommended) is to have the<br />

writer and readers open the dataset with the NF<strong>90</strong> SHARE flag, and then it will not be<br />

necessary to call NF<strong>90</strong> SYNC at all. However, the NF<strong>90</strong> SYNC function still provides<br />

f<strong>in</strong>er granularity than the NF<strong>90</strong> SHARE flag, if only a few netCDF accesses need to be<br />

synchronized among processes.<br />

It is important to note that changes to the ancillary data, such as attribute values, are<br />

not propagated automatically by use of the NF<strong>90</strong> SHARE flag. Use of the NF<strong>90</strong> SYNC<br />

function is still required <strong>for</strong> this purpose.<br />

Shar<strong>in</strong>g datasets when the writer enters def<strong>in</strong>e mode to change the data schema requires<br />

extra care. In previous releases, after the writer left def<strong>in</strong>e mode, the readers were left


Chapter 2: Datasets 17<br />

look<strong>in</strong>g at an old copy of the dataset, s<strong>in</strong>ce the changes were made to a new copy. The<br />

only way readers could see the changes was by clos<strong>in</strong>g and reopen<strong>in</strong>g the dataset. Now the<br />

changes are made <strong>in</strong> place, but readers have no knowledge that their <strong>in</strong>ternal tables are now<br />

<strong>in</strong>consistent with the new dataset schema. If netCDF datasets are shared across redef<strong>in</strong>ition,<br />

some mechanism external to the netCDF library must be provided that prevents access by<br />

readers dur<strong>in</strong>g redef<strong>in</strong>ition and causes the readers to call NF<strong>90</strong> SYNC be<strong>for</strong>e any subsequent<br />

access.<br />

When call<strong>in</strong>g NF<strong>90</strong> SYNC, the netCDF dataset must be <strong>in</strong> data mode. A netCDF<br />

dataset <strong>in</strong> def<strong>in</strong>e mode is synchronized to disk only when NF<strong>90</strong> ENDDEF is called. A process<br />

that is read<strong>in</strong>g a netCDF dataset that another process is writ<strong>in</strong>g may call NF<strong>90</strong> SYNC<br />

to get updated with the changes made to the data by the writ<strong>in</strong>g process (e.g., the number<br />

of records written), without hav<strong>in</strong>g to close and reopen the dataset.<br />

Data is automatically synchronized to disk when a netCDF dataset is closed, or whenever<br />

you leave def<strong>in</strong>e mode.<br />

Usage<br />

function nf<strong>90</strong>_sync(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_sync<br />

ncid<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Errors<br />

NF<strong>90</strong> SYNC returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the returned<br />

status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The netCDF dataset is <strong>in</strong> def<strong>in</strong>e mode.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> SYNC to synchronize the disk writes of a netCDF dataset<br />

named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! write data or change attributes<br />

...<br />

status = NF<strong>90</strong>_SYNC(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)


18 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

2.12 NF<strong>90</strong> ABORT<br />

You no longer need to call this function, s<strong>in</strong>ce it is called automatically by NF<strong>90</strong> CLOSE <strong>in</strong><br />

case the dataset is <strong>in</strong> def<strong>in</strong>e mode and someth<strong>in</strong>g goes wrong with committ<strong>in</strong>g the changes.<br />

The function NF<strong>90</strong> ABORT just closes the netCDF dataset, if not <strong>in</strong> def<strong>in</strong>e mode. If the<br />

dataset is be<strong>in</strong>g created and is still <strong>in</strong> def<strong>in</strong>e mode, the dataset is deleted. If def<strong>in</strong>e mode<br />

was entered by a call to NF<strong>90</strong> REDEF, the netCDF dataset is restored to its state be<strong>for</strong>e<br />

def<strong>in</strong>ition mode was entered and the dataset is closed.<br />

Usage<br />

function nf<strong>90</strong>_abort(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_abort<br />

ncid<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Errors<br />

NF<strong>90</strong> ABORT returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the returned<br />

status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• When called from def<strong>in</strong>e mode while creat<strong>in</strong>g a netCDF dataset, deletion of the dataset<br />

failed.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> ABORT to back out of redef<strong>in</strong>itions of a dataset named<br />

foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, LatDimID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_redef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_def_dim(ncid, "Lat", 18, LatDimID)<br />

if (status /= nf<strong>90</strong>_noerr) then ! Dimension def<strong>in</strong>ition failed<br />

call handle_err(status)<br />

status = nf<strong>90</strong>_abort(ncid) ! Abort redef<strong>in</strong>itions<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

end if<br />

...


Chapter 2: Datasets 19<br />

2.13 NF<strong>90</strong> SET FILL<br />

This function is <strong>in</strong>tended <strong>for</strong> advanced usage, to optimize writes under some circumstances<br />

described below. The function NF<strong>90</strong> SET FILL sets the fill mode <strong>for</strong> a netCDF dataset<br />

open <strong>for</strong> writ<strong>in</strong>g and returns the current fill mode <strong>in</strong> a return parameter. The fill mode can<br />

be specified as either NF<strong>90</strong> FILL or NF<strong>90</strong> NOFILL. The default behavior correspond<strong>in</strong>g<br />

to NF<strong>90</strong> FILL is that data is pre-filled with fill values, that is fill values are written when<br />

you create non-record variables or when you write a value beyond data that has not yet<br />

been written. This makes it possible to detect attempts to read data be<strong>for</strong>e it was written.<br />

See Section 4.9 [Fill Values], page 42, <strong>for</strong> more <strong>in</strong><strong>for</strong>mation on the use of fill values. See<br />

Section 5.2 [Attribute Conventions], page 45, <strong>for</strong> <strong>in</strong><strong>for</strong>mation about how to def<strong>in</strong>e your own<br />

fill values.<br />

The behavior correspond<strong>in</strong>g to NF<strong>90</strong> NOFILL overrides the default behavior of prefill<strong>in</strong>g<br />

data with fill values. This can be used to enhance per<strong>for</strong>mance, because it avoids<br />

the duplicate writes that occur when the netCDF library writes fill values that are later<br />

overwritten with data.<br />

A value <strong>in</strong>dicat<strong>in</strong>g which mode the netCDF dataset was already <strong>in</strong> is returned. You can<br />

use this value to temporarily change the fill mode of an open netCDF dataset and then<br />

restore it to the previous mode.<br />

After you turn on NF<strong>90</strong> NOFILL mode <strong>for</strong> an open netCDF dataset, you must be certa<strong>in</strong><br />

to write valid data <strong>in</strong> all the positions that will later be read. Note that nofill mode is only<br />

a transient property of a netCDF dataset open <strong>for</strong> writ<strong>in</strong>g: if you close and reopen the<br />

dataset, it will revert to the default behavior. You can also revert to the default behavior<br />

by call<strong>in</strong>g NF<strong>90</strong> SET FILL aga<strong>in</strong> to explicitly set the fill mode to NF<strong>90</strong> FILL.<br />

There are three situations where it is advantageous to set nofill mode:<br />

1. Creat<strong>in</strong>g and <strong>in</strong>itializ<strong>in</strong>g a netCDF dataset. In this case, you should set nofill mode<br />

be<strong>for</strong>e call<strong>in</strong>g NF<strong>90</strong> ENDDEF and then write completely all non-record variables and<br />

the <strong>in</strong>itial records of all the record variables you want to <strong>in</strong>itialize.<br />

2. Extend<strong>in</strong>g an exist<strong>in</strong>g record-oriented netCDF dataset. Set nofill mode after open<strong>in</strong>g<br />

the dataset <strong>for</strong> writ<strong>in</strong>g, then append the additional records to the dataset completely,<br />

leav<strong>in</strong>g no <strong>in</strong>terven<strong>in</strong>g unwritten records.<br />

3. Add<strong>in</strong>g new variables that you are go<strong>in</strong>g to <strong>in</strong>itialize to an exist<strong>in</strong>g netCDF dataset. Set<br />

nofill mode be<strong>for</strong>e call<strong>in</strong>g NF<strong>90</strong> ENDDEF then write all the new variables completely.<br />

If the netCDF dataset has an unlimited dimension and the last record was written while<br />

<strong>in</strong> nofill mode, then the dataset may be shorter than if nofill mode was not set, but this<br />

will be completely transparent if you access the data only through the netCDF <strong>in</strong>terfaces.<br />

The use of this feature may not be available (or even needed) <strong>in</strong> future releases. Programmers<br />

are cautioned aga<strong>in</strong>st heavy reliance upon this feature.<br />

Usage<br />

function nf<strong>90</strong>_set_fill(ncid, fillmode, old_mode)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, fillmode<br />

<strong>in</strong>teger, <strong>in</strong>tent(out) :: old_mode<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_set_fill


20 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

ncid<br />

fillmode<br />

old_mode<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Desired fill mode <strong>for</strong> the dataset, either NF<strong>90</strong> NOFILL or NF<strong>90</strong> FILL.<br />

Returned current fill mode of the dataset be<strong>for</strong>e this call, either NF<strong>90</strong> NOFILL<br />

or NF<strong>90</strong> FILL.<br />

Errors<br />

NF<strong>90</strong> SET FILL returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

• The specified netCDF ID refers to a dataset open <strong>for</strong> read-only access.<br />

• The fill mode argument is neither NF<strong>90</strong> NOFILL nor NF<strong>90</strong> FILL..<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> SET FILL to set nofill mode <strong>for</strong> subsequent writes of a<br />

netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, oldMode<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! Write data with prefill<strong>in</strong>g behavior<br />

...<br />

status = nf<strong>90</strong>_set_fill(ncid, nf<strong>90</strong>_nofill, oldMode)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! Write data with no prefill<strong>in</strong>g<br />

...


Chapter 3: Dimensions 21<br />

3 Dimensions<br />

3.1 Dimensions Introduction<br />

Dimensions <strong>for</strong> a netCDF dataset are def<strong>in</strong>ed when it is created, while the netCDF dataset<br />

is <strong>in</strong> def<strong>in</strong>e mode. Additional dimensions may be added later by reenter<strong>in</strong>g def<strong>in</strong>e mode. A<br />

netCDF dimension has a name and a length. At most one dimension <strong>in</strong> a netCDF dataset<br />

can have the unlimited length, which means variables us<strong>in</strong>g this dimension can grow along<br />

this dimension.<br />

There is a suggested limit (512) to the number of dimensions that can be def<strong>in</strong>ed <strong>in</strong> a<br />

s<strong>in</strong>gle netCDF dataset. The limit is the value of the constant NF<strong>90</strong> MAX DIMS. The purpose<br />

of the limit is to make writ<strong>in</strong>g generic applications simpler. They need only provide an<br />

array of NF<strong>90</strong> MAX DIMS dimensions to handle any netCDF dataset. The implementation<br />

of the netCDF library does not en<strong>for</strong>ce this advisory maximum, so it is possible to use<br />

more dimensions, if necessary, but netCDF utilities that assume the advisory maximums<br />

may not be able to handle the result<strong>in</strong>g netCDF datasets.<br />

Ord<strong>in</strong>arily, the name and length of a dimension are fixed when the dimension is first<br />

def<strong>in</strong>ed. The name may be changed later, but the length of a dimension (other than the<br />

unlimited dimension) cannot be changed without copy<strong>in</strong>g all the data to a new netCDF<br />

dataset with a redef<strong>in</strong>ed dimension length.<br />

A netCDF dimension <strong>in</strong> an open netCDF dataset is referred to by a small <strong>in</strong>teger called<br />

a dimension ID. In the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface, dimension IDs are 1, 2, 3, ..., <strong>in</strong> the order <strong>in</strong><br />

which the dimensions were def<strong>in</strong>ed.<br />

Operations supported on dimensions are:<br />

• Create a dimension, given its name and length.<br />

• Get a dimension ID from its name.<br />

• Get a dimension’s name and length from its ID.<br />

• Rename a dimension.<br />

3.2 NF<strong>90</strong> DEF DIM<br />

The function NF<strong>90</strong> DEF DIM adds a new dimension to an open netCDF dataset <strong>in</strong> def<strong>in</strong>e<br />

mode. It returns (as an argument) a dimension ID, given the netCDF ID, the dimension<br />

name, and the dimension length. At most one unlimited length dimension, called the record<br />

dimension, may be def<strong>in</strong>ed <strong>for</strong> each netCDF dataset.<br />

Usage<br />

ncid<br />

function nf<strong>90</strong>_def_dim(ncid, name, len, dimid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: len<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_def_dim<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.


22 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

name<br />

len<br />

dimid<br />

Dimension name. Must beg<strong>in</strong> with an alphabetic character, followed by zero or<br />

more alphanumeric characters <strong>in</strong>clud<strong>in</strong>g the underscore (’ ’). Case is significant.<br />

Length of dimension; that is, number of values <strong>for</strong> this dimension as an <strong>in</strong>dex to<br />

variables that use it. This should be either a positive <strong>in</strong>teger or the predef<strong>in</strong>ed<br />

constant NF<strong>90</strong> UNLIMITED.<br />

Returned dimension ID.<br />

Errors<br />

NF<strong>90</strong> DEF DIM returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The netCDF dataset is not <strong>in</strong> def<strong>in</strong>ition mode.<br />

• The specified dimension name is the name of another exist<strong>in</strong>g dimension.<br />

• The specified length is not greater than zero.<br />

• The specified length is unlimited, but there is already an unlimited length dimension<br />

def<strong>in</strong>ed <strong>for</strong> this netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> DEF DIM to create a dimension named lat of length 18<br />

and a unlimited dimension named rec <strong>in</strong> a new netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, LatDimID, RecordDimID<br />

...<br />

status = nf<strong>90</strong>_create("foo.nc", nf<strong>90</strong>_noclobber, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_def_dim(ncid, "Lat", 18, LatDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_def_dim(ncid, "Record", nf<strong>90</strong>_unlimited, RecordDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

3.3 NF<strong>90</strong> INQ DIMID<br />

The function NF<strong>90</strong> INQ DIMID returns (as an argument) the ID of a netCDF dimension,<br />

given the name of the dimension. If ndims is the number of dimensions def<strong>in</strong>ed <strong>for</strong> a netCDF<br />

dataset, each dimension has an ID between 1 and ndims.<br />

Usage<br />

function nf<strong>90</strong>_<strong>in</strong>q_dimid(ncid, name, dimid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_dimid


Chapter 3: Dimensions 23<br />

ncid<br />

name<br />

dimid<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Dimension name, a character str<strong>in</strong>g beg<strong>in</strong>n<strong>in</strong>g with a letter and followed by any<br />

sequence of letters, digits, or underscore (’ ’) characters. Case is significant <strong>in</strong><br />

dimension names.<br />

Returned dimension ID.<br />

Errors<br />

NF<strong>90</strong> INQ DIMID returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The name that was specified is not the name of a dimension <strong>in</strong> the netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> INQ DIMID to determ<strong>in</strong>e the dimension ID of a dimension<br />

named lat, assumed to have been def<strong>in</strong>ed previously <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named<br />

foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, LatDimID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_dimid(ncid, "Lat", LatDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

3.4 NF<strong>90</strong> Inquire Dimension<br />

This function <strong>in</strong><strong>for</strong>mation about a netCDF dimension. In<strong>for</strong>mation about a dimension<br />

<strong>in</strong>cludes its name and its length. The length <strong>for</strong> the unlimited dimension, if any, is the<br />

number of records written so far.<br />

Usage<br />

ncid<br />

dimid<br />

function nf<strong>90</strong>_Inquire_Dimension(ncid, dimid, name, len)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, dimid<br />

character (len = *), optional, <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: len<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Dimension<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Dimension ID, from a previous call to NF<strong>90</strong> INQ DIMID or NF<strong>90</strong> DEF DIM.<br />

name Returned dimension name. The caller must allocate space <strong>for</strong> the returned<br />

name. The maximum possible length, <strong>in</strong> characters, of a dimension name is<br />

given by the predef<strong>in</strong>ed constant NF<strong>90</strong> MAX NAME.


24 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

len<br />

Returned length of dimension. For the unlimited dimension, this is the current<br />

maximum value used <strong>for</strong> writ<strong>in</strong>g any variables with this dimension, that is the<br />

maximum record number.<br />

Errors<br />

These functions return the value NF<strong>90</strong> NOERR if no errors occurred.<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The dimension ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Otherwise, the<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> INQ DIM to determ<strong>in</strong>e the length of a dimension named<br />

lat, and the name and current maximum length of the unlimited dimension <strong>for</strong> an exist<strong>in</strong>g<br />

netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, LatDimID, RecordDimID<br />

<strong>in</strong>teger :: nLats, nRecords<br />

character(len = nf<strong>90</strong>_max_name) :: RecordDimName<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Get ID of unlimited dimension<br />

status = nf<strong>90</strong>_Inquire(ncid, unlimitedDimId = RecordDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_dimid(ncid, "Lat", LatDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! How many values of "lat" are there?<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, LatDimID, len = nLats)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! What is the name of the unlimited dimension, how many records are there?<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, RecordDimID, &<br />

name = RecordDimName, len = Records)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

3.5 NF<strong>90</strong> RENAME DIM<br />

The function NF<strong>90</strong> RENAME DIM renames an exist<strong>in</strong>g dimension <strong>in</strong> a netCDF dataset<br />

open <strong>for</strong> writ<strong>in</strong>g. If the new name is longer than the old name, the netCDF dataset must<br />

be <strong>in</strong> def<strong>in</strong>e mode. You cannot rename a dimension to have the same name as another<br />

dimension.<br />

Usage<br />

function nf<strong>90</strong>_rename_dim(ncid, dimid, name)


Chapter 3: Dimensions 25<br />

ncid<br />

dimid<br />

name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_dim<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Dimension ID, from a previous call to NF<strong>90</strong> INQ DIMID or NF<strong>90</strong> DEF DIM.<br />

New dimension name.<br />

Errors<br />

NF<strong>90</strong> RENAME DIM returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The new name is the name of another dimension.<br />

• The dimension ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

• The new name is longer than the old name and the netCDF dataset is not <strong>in</strong> def<strong>in</strong>e<br />

mode.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> RENAME DIM to rename the dimension lat to latitude <strong>in</strong><br />

an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, LatDimID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! Put <strong>in</strong> def<strong>in</strong>e mode so we can rename the dimension<br />

status = nf<strong>90</strong>_redef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Get the dimension ID <strong>for</strong> "Lat"...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_dimid(ncid, "Lat", LatDimID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! ... and change the name to "Latitude".<br />

status = nf<strong>90</strong>_rename_dim(ncid, LatDimID, "Latitude")<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Leave def<strong>in</strong>e mode<br />

status = nf<strong>90</strong>_enddef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)


26 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide


Chapter 4: Variables 27<br />

4 Variables<br />

4.1 Variables Introduction<br />

Variables <strong>for</strong> a netCDF dataset are def<strong>in</strong>ed when the dataset is created, while the netCDF<br />

dataset is <strong>in</strong> def<strong>in</strong>e mode. Other variables may be added later by reenter<strong>in</strong>g def<strong>in</strong>e mode.<br />

A netCDF variable has a name, a type, and a shape, which are specified when it is def<strong>in</strong>ed.<br />

A variable may also have values, which are established later <strong>in</strong> data mode.<br />

Ord<strong>in</strong>arily, the name, type, and shape are fixed when the variable is first def<strong>in</strong>ed. The<br />

name may be changed, but the type and shape of a variable cannot be changed. However,<br />

a variable def<strong>in</strong>ed <strong>in</strong> terms of the unlimited dimension can grow without bound <strong>in</strong> that<br />

dimension.<br />

A netCDF variable <strong>in</strong> an open netCDF dataset is referred to by a small <strong>in</strong>teger called a<br />

variable ID.<br />

Variable IDs reflect the order <strong>in</strong> which variables were def<strong>in</strong>ed with<strong>in</strong> a netCDF dataset.<br />

Variable IDs are 1, 2, 3,..., <strong>in</strong> the order <strong>in</strong> which the variables were def<strong>in</strong>ed. A function is<br />

available <strong>for</strong> gett<strong>in</strong>g the variable ID from the variable name and vice-versa.<br />

Attributes Chapter 5 [Attributes], page 45 may be associated with a variable to specify<br />

such properties as units.<br />

Operations supported on variables are:<br />

• Create a variable, given its name, data type, and shape.<br />

• Get a variable ID from its name.<br />

• Get a variable’s name, data type, shape, and number of attributes from its ID.<br />

• Put a data value <strong>in</strong>to a variable, given variable ID, <strong>in</strong>dices, and value.<br />

• Put an array of values <strong>in</strong>to a variable, given variable ID, corner <strong>in</strong>dices, edge lengths,<br />

and a block of values.<br />

• Put a subsampled or mapped array-section of values <strong>in</strong>to a variable, given variable ID,<br />

corner <strong>in</strong>dices, edge lengths, stride vector, <strong>in</strong>dex mapp<strong>in</strong>g vector, and a block of values.<br />

• Get a data value from a variable, given variable ID and <strong>in</strong>dices.<br />

• Get an array of values from a variable, given variable ID, corner <strong>in</strong>dices, and edge<br />

lengths.<br />

• Get a subsampled or mapped array-section of values from a variable, given variable ID,<br />

corner <strong>in</strong>dices, edge lengths, stride vector, and <strong>in</strong>dex mapp<strong>in</strong>g vector.<br />

• Rename a variable.<br />

4.2 Language Types Correspond<strong>in</strong>g to netCDF external<br />

data types<br />

The follow<strong>in</strong>g table gives the netCDF external data types and the correspond<strong>in</strong>g type<br />

constants <strong>for</strong> def<strong>in</strong><strong>in</strong>g variables <strong>in</strong> the FORTRAN <strong>in</strong>terface:<br />

Type FORTRAN API Mnemonic Bits<br />

byte NF<strong>90</strong> BYTE 8


28 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

char NF<strong>90</strong> CHAR 8<br />

short NF<strong>90</strong> SHORT 16<br />

<strong>in</strong>t NF<strong>90</strong> INT 32<br />

float NF<strong>90</strong> FLOAT 32<br />

double NF<strong>90</strong> DOUBLE 64<br />

The first column gives the netCDF external data type, which is the same as the CDL data<br />

type. The next column gives the correspond<strong>in</strong>g <strong>Fortran</strong> <strong>90</strong> parameter <strong>for</strong> use <strong>in</strong> netCDF<br />

functions (the parameters are def<strong>in</strong>ed <strong>in</strong> the netCDF <strong>Fortran</strong> <strong>90</strong> module netcdf.f<strong>90</strong>). The<br />

last column gives the number of bits used <strong>in</strong> the external representation of values of the<br />

correspond<strong>in</strong>g type.<br />

Note that there are no netCDF types correspond<strong>in</strong>g to 64-bit <strong>in</strong>tegers or to characters<br />

wider than 8 bits <strong>in</strong> the current version of the netCDF library.<br />

4.3 Create a Variable: NF<strong>90</strong>_DEF_VAR<br />

The function NF<strong>90</strong> DEF VAR adds a new variable to an open netCDF dataset <strong>in</strong> def<strong>in</strong>e<br />

mode. It returns (as an argument) a variable ID, given the netCDF ID, the variable name,<br />

the variable type, the number of dimensions, and a list of the dimension IDs.<br />

Usage<br />

ncid<br />

name<br />

xtype<br />

nvdims<br />

vdims<br />

varid<br />

function nf<strong>90</strong>_def_var(ncid, name, xtype, dimids, varid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: xtype<br />

<strong>in</strong>teger, dimension(:), <strong>in</strong>tent( <strong>in</strong>) :: dimids<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_def_var<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable name. Must beg<strong>in</strong> with an alphabetic character, followed by zero or<br />

more alphanumeric characters <strong>in</strong>clud<strong>in</strong>g the underscore (’ ’). Case is significant.<br />

One of the set of predef<strong>in</strong>ed netCDF external data types. The type of this parameter,<br />

NF<strong>90</strong> TYPE, is def<strong>in</strong>ed <strong>in</strong> the netCDF header file. The valid netCDF<br />

external data types are NF<strong>90</strong> BYTE, NF<strong>90</strong> CHAR, NF<strong>90</strong> SHORT, NF<strong>90</strong> INT,<br />

NF<strong>90</strong> FLOAT, and NF<strong>90</strong> DOUBLE.<br />

Number of dimensions <strong>for</strong> the variable. For example, 2 specifies a matrix, 1 specifies<br />

a vector, and 0 means the variable is a scalar with no dimensions. Must not<br />

be negative or greater than the predef<strong>in</strong>ed constant NF<strong>90</strong> MAX VAR DIMS.<br />

Vector of ndims dimension IDs correspond<strong>in</strong>g to the variable dimensions. If the<br />

ID of the unlimited dimension is <strong>in</strong>cluded, it must be first. This argument is<br />

ignored if ndims is 0.<br />

Returned variable ID.


Chapter 4: Variables 29<br />

Errors<br />

NF<strong>90</strong> DEF VAR returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The netCDF dataset is not <strong>in</strong> def<strong>in</strong>e mode.<br />

• The specified variable name is the name of another exist<strong>in</strong>g variable.<br />

• The specified type is not a valid netCDF type.<br />

• The specified number of dimensions is negative or more than the constant<br />

NF<strong>90</strong> MAX VAR DIMS, the maximum number of dimensions permitted <strong>for</strong> a<br />

netCDF variable.<br />

• One or more of the dimension IDs <strong>in</strong> the list of dimensions is not a valid dimension ID<br />

<strong>for</strong> the netCDF dataset.<br />

• The number of variables would exceed the constant NF<strong>90</strong> MAX VARS, the maximum<br />

number of variables permitted <strong>in</strong> a netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> DEF VAR to create a variable named rh of type double<br />

with three dimensions, time, lat, and lon <strong>in</strong> a new netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: status, ncid<br />

<strong>in</strong>teger :: LonDimId, LatDimId, TimeDimId<br />

<strong>in</strong>teger :: RhVarId<br />

...<br />

status = nf<strong>90</strong>_create("foo.nc", nf<strong>90</strong>_NoClobber, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

...<br />

! Def<strong>in</strong>e the dimensions<br />

status = nf<strong>90</strong>_def_dim(ncid, "lat", 5, LatDimId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

status = nf<strong>90</strong>_def_dim(ncid, "lon", 10, LonDimId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

status = nf<strong>90</strong>_def_dim(ncid, "time", nf<strong>90</strong>_unlimited, TimeDimId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

...<br />

! Def<strong>in</strong>e the variable<br />

status = nf<strong>90</strong>_def_var(ncid, "rh", nf<strong>90</strong>_double, &<br />

(/ LonDimId, LatDimID, TimeDimID /), RhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

4.4 Get a Variable ID from Its Name: NF<strong>90</strong> INQ VARID<br />

The function NF<strong>90</strong> INQ VARID returns the ID of a netCDF variable, given its name.


30 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Usage<br />

ncid<br />

name<br />

varid<br />

Errors<br />

function nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, name, varid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: varid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_varid<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable name <strong>for</strong> which ID is desired.<br />

Returned variable ID.<br />

NF<strong>90</strong> INQ VARID returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified variable name is not a valid name <strong>for</strong> a variable <strong>in</strong> the specified netCDF<br />

dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> INQ VARID to f<strong>in</strong>d out the ID of a variable named rh <strong>in</strong><br />

an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: status, ncid, RhVarId<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

4.5 Get In<strong>for</strong>mation about a Variable from Its ID:<br />

NF<strong>90</strong> Inquire Variable<br />

NF<strong>90</strong> Inquire Variable returns <strong>in</strong><strong>for</strong>mation about a netCDF variable given its ID. In<strong>for</strong>mation<br />

about a variable <strong>in</strong>cludes its name, type, number of dimensions, a list of dimension IDs<br />

describ<strong>in</strong>g the shape of the variable, and the number of variable attributes that have been<br />

assigned to the variable.<br />

Usage<br />

function nf<strong>90</strong>_Inquire_Variable(ncid, varid, name, xtype, ndims, dimids, nAtts)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), optional, <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: xtype, ndims


Chapter 4: Variables 31<br />

ncid<br />

varid<br />

name<br />

xtype<br />

ndims<br />

dimids<br />

natts<br />

<strong>in</strong>teger, dimension(*), optional, <strong>in</strong>tent(out) :: dimids<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: nAtts<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Variable<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID.<br />

Returned variable name. The caller must allocate space <strong>for</strong> the returned name.<br />

The maximum possible length, <strong>in</strong> characters, of a variable name is given by the<br />

predef<strong>in</strong>ed constant NF<strong>90</strong> MAX NAME.<br />

Returned variable type, one of the set of predef<strong>in</strong>ed netCDF external data types.<br />

The type of this parameter, NF<strong>90</strong> TYPE, is def<strong>in</strong>ed <strong>in</strong> the netCDF header<br />

file. The valid netCDF external data types are NF<strong>90</strong> BYTE, NF<strong>90</strong> CHAR,<br />

NF<strong>90</strong> SHORT, NF<strong>90</strong> INT, NF<strong>90</strong> FLOAT, AND NF<strong>90</strong> DOUBLE.<br />

Returned number of dimensions the variable was def<strong>in</strong>ed as us<strong>in</strong>g. For example,<br />

2 <strong>in</strong>dicates a matrix, 1 <strong>in</strong>dicates a vector, and 0 means the variable is a scalar<br />

with no dimensions.<br />

Returned vector of *ndimsp dimension IDs correspond<strong>in</strong>g to the variable dimensions.<br />

The caller must allocate enough space <strong>for</strong> a vector of at least *ndimsp<br />

<strong>in</strong>tegers to be returned. The maximum possible number of dimensions <strong>for</strong> a<br />

variable is given by the predef<strong>in</strong>ed constant NF<strong>90</strong> MAX VAR DIMS.<br />

Returned number of variable attributes assigned to this variable.<br />

These functions return the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> INQ VAR to f<strong>in</strong>d out about a variable named rh <strong>in</strong> an<br />

exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: status, ncid, &<br />

RhVarId &<br />

numDims, numAtts<br />

<strong>in</strong>teger, dimension(nf<strong>90</strong>_max_var_dims) :: rhDimIds<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_error(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Var(ncid, RhVarId, ndims = numDims, natts = numAtts)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)


32 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

status = nf<strong>90</strong>_Inquire_Var(ncid, RhVarId, dimids = rhDimIds(:numDims))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

4.6 Writ<strong>in</strong>g Data Values: NF<strong>90</strong> PUT VAR<br />

The function NF<strong>90</strong> PUT VAR puts one or more data values <strong>in</strong>to the variable of an open<br />

netCDF dataset that is <strong>in</strong> data mode. Required <strong>in</strong>puts are the netCDF ID, the variable ID,<br />

and one or more data values. Optional <strong>in</strong>puts may <strong>in</strong>dicate the start<strong>in</strong>g position of the data<br />

values <strong>in</strong> the netCDF variable (argument start), the sampl<strong>in</strong>g frequency with which data<br />

values are written <strong>in</strong>to the netCDF variable (argument stride), and a mapp<strong>in</strong>g between the<br />

dimensions of the data array and the netCDF variable (argument map). The values to be<br />

written are associated with the netCDF variable by assum<strong>in</strong>g that the first dimension of<br />

the netCDF variable varies fastest <strong>in</strong> the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface. Data values converted to the<br />

external type of the variable, if necessary.<br />

Take care when us<strong>in</strong>g the simplest <strong>for</strong>ms of this <strong>in</strong>terface with record variables when<br />

you don’t specify how many records are to be written. If you try to write all the values<br />

of a record variable <strong>in</strong>to a netCDF file that has no record data yet (hence has 0 records),<br />

noth<strong>in</strong>g will be written. Similarly, if you try to write all of a record variable but there are<br />

more records <strong>in</strong> the file than you assume, more data may be written to the file than you<br />

supply, which may result <strong>in</strong> a segmentation violation.<br />

Usage<br />

ncid<br />

varid<br />

values<br />

start<br />

count<br />

function nf<strong>90</strong>_put_var(ncid, varid, values, start, count, stride, map)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

any valid type, scalar or array of any rank, &<br />

<strong>in</strong>tent( <strong>in</strong>) :: values<br />

<strong>in</strong>teger, dimension(:), optional, <strong>in</strong>tent( <strong>in</strong>) :: start, count, stride, map<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_put_var<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID.<br />

The data value(s) to be written. The data may be of any type, and may be<br />

a scalar or an array of any rank. You cannot put CHARACTER data <strong>in</strong>to a<br />

numeric variable or numeric data <strong>in</strong>to a text variable. For numeric data, if the<br />

type of data differs from the netCDF variable type, type conversion will occur.<br />

See section “Type Conversion” <strong>in</strong> <strong>NetCDF</strong> Users Guide.<br />

A vector of <strong>in</strong>tegers specify<strong>in</strong>g the <strong>in</strong>dex <strong>in</strong> the variable where the first (or only)<br />

of the data values will be written. The <strong>in</strong>dices are relative to 1, so <strong>for</strong> example,<br />

the first data value of a variable would have <strong>in</strong>dex (1, 1, ..., 1). The elements of<br />

start correspond, <strong>in</strong> order, to the variable’s dimensions. Hence, if the variable is<br />

a record variable, the last <strong>in</strong>dex would correspond to the start<strong>in</strong>g record number<br />

<strong>for</strong> writ<strong>in</strong>g the data values.<br />

By default, start(:) = 1.<br />

A vector of <strong>in</strong>tegers specify<strong>in</strong>g the number of <strong>in</strong>dices selected along each dimension.<br />

To write a s<strong>in</strong>gle value, <strong>for</strong> example, specify count as (1, 1, ..., 1). The


Chapter 4: Variables 33<br />

stride<br />

imap<br />

elements of count correspond, <strong>in</strong> order, to the variable’s dimensions. Hence,<br />

if the variable is a record variable, the last element of count corresponds to a<br />

count of the number of records to write.<br />

By default, count(:numDims) = shape(values) and count(numDims + 1:) = 1,<br />

where numDims = size(shape(values)).<br />

A vector of <strong>in</strong>tegers that specifies the sampl<strong>in</strong>g <strong>in</strong>terval along each dimension of<br />

the netCDF variable. The elements of the stride vector correspond, <strong>in</strong> order, to<br />

the netCDF variable’s dimensions (stride(1) gives the sampl<strong>in</strong>g <strong>in</strong>terval along<br />

the most rapidly vary<strong>in</strong>g dimension of the netCDF variable). Sampl<strong>in</strong>g <strong>in</strong>tervals<br />

are specified <strong>in</strong> type-<strong>in</strong>dependent units of elements (a value of 1 selects consecutive<br />

elements of the netCDF variable along the correspond<strong>in</strong>g dimension, a<br />

value of 2 selects every other element, etc.).<br />

By default, stride(:) = 1.<br />

A vector of <strong>in</strong>tegers that specifies the mapp<strong>in</strong>g between the dimensions of a<br />

netCDF variable and the <strong>in</strong>-memory structure of the <strong>in</strong>ternal data array. The<br />

elements of the <strong>in</strong>dex mapp<strong>in</strong>g vector correspond, <strong>in</strong> order, to the netCDF<br />

variable’s dimensions (map(1) gives the distance between elements of the <strong>in</strong>ternal<br />

array correspond<strong>in</strong>g to the most rapidly vary<strong>in</strong>g dimension of the netCDF<br />

variable). Distances between elements are specified <strong>in</strong> units of elements.<br />

By default, edgeLengths = shape(values), and map = (/ 1, (product(edgeLengths(:i)),<br />

i = 1, size(edgeLengths) - 1) /), that is, there is no<br />

mapp<strong>in</strong>g.<br />

Use of <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>tr<strong>in</strong>sic functions (<strong>in</strong>clud<strong>in</strong>g reshape, transpose, and spread)<br />

may let you avoid us<strong>in</strong>g this argument.<br />

Errors<br />

NF<strong>90</strong> PUT VAR1 type returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified <strong>in</strong>dices were out of range <strong>for</strong> the rank of the specified variable. For<br />

example, a negative <strong>in</strong>dex or an <strong>in</strong>dex that is larger than the correspond<strong>in</strong>g dimension<br />

length will cause an error.<br />

• The specified value is out of the range of values representable by the external data type<br />

of the variable.<br />

• The specified netCDF is <strong>in</strong> def<strong>in</strong>e mode rather than data mode.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> PUT VAR to set the (4,3,2) element of the variable named<br />

rh to 0.5 <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc. For simplicity <strong>in</strong> this example, we<br />

assume that we know that rh is dimensioned with lon, lat, and time, so we want to set the<br />

value of rh that corresponds to the fourth lon value, the third lat value, and the second<br />

time value:


34 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncId, rhVarId, status<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId, 0.5, start = (/ 4, 3, 2 /) )<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

In this example we use NF<strong>90</strong> PUT VAR to add or change all the values of the variable<br />

named rh to 0.5 <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc. We assume that we know<br />

that rh is dimensioned with lon, lat, and time. In this example we query the netCDF file to<br />

discover the lengths of the dimensions, then use the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>tr<strong>in</strong>sic function reshape to<br />

create a temporary array of data values which is the same shape as the netCDF variable.<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncId, rhVarId,status, &<br />

lonDimID, latDimId, timeDimId, &<br />

numLons, numLats, numTimes, &<br />

i<br />

<strong>in</strong>teger, dimension(nf<strong>90</strong>_max_var_dims) :: dimIDs<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

! How big is the netCDF variable, that is, what are the lengths of<br />

! its constituent dimensions?<br />

status = nf<strong>90</strong>_Inquire_Variable(ncid, rhVarId, dimids = dimIDs)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(1), len = numLons)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(2), len = numLats)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(3), len = numTimes)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

! Make a temporary array the same shape as the netCDF variable.<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId, &<br />

reshape( &<br />

(/ (0.5, i = 1, numLons * numLats * numTimes) /) , &<br />

shape = (/ numLons, numLats, numTimes /) )<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)


Chapter 4: Variables 35<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> PUT VAR to add or change a section of the variable<br />

named rh to 0.5 <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc. For simplicity <strong>in</strong> this example,<br />

we assume that we know that rh is dimensioned with lon, lat, and time, that there are ten<br />

lon values, five lat values, and three time values, and that we want to replace all the values<br />

at the last time.<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 10, numLats = 5, numTimes = 3<br />

real, dimension(numLons, numLats) &<br />

:: rhValues<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

! Fill <strong>in</strong> all values at the last time<br />

rhValues(:, :) = 0.5<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId,rhvalues, &<br />

start = (/ 1, 1, numTimes /), &<br />

count = (/ numLats, numLons, 1 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

Here is an example of us<strong>in</strong>g NF PUT VAR to write every other po<strong>in</strong>t of a netCDF<br />

variable named rh hav<strong>in</strong>g dimensions (6, 4).<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) &<br />

:: rhValues = 0.5<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

! Fill <strong>in</strong> every other value us<strong>in</strong>g an array section<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId, rhValues(::2, ::2), &<br />

stride = (/ 2, 2 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

The follow<strong>in</strong>g map vector shows the default mapp<strong>in</strong>g between a 2x3x4 netCDF variable<br />

and an <strong>in</strong>ternal array of the same shape:<br />

real, dimension(2, 3, 4):: a ! same shape as netCDF variable<br />

<strong>in</strong>teger, dimension(3) :: map = (/ 1, 2, 6 /)


36 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

! netCDF dimension <strong>in</strong>ter-element distance<br />

! ---------------- ----------------------<br />

! most rapidly vary<strong>in</strong>g 1<br />

! <strong>in</strong>termediate 2 (= map(1)*2)<br />

! most slowly vary<strong>in</strong>g 6 (= map(2)*3)<br />

Us<strong>in</strong>g the map vector above obta<strong>in</strong>s the same result as simply not pass<strong>in</strong>g a map vector<br />

at all.<br />

Here is an example of us<strong>in</strong>g nf<strong>90</strong> put var to write a netCDF variable named rh whose<br />

dimensions are the transpose of the <strong>Fortran</strong> <strong>90</strong> array:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) :: rhValues<br />

! netCDF variable has dimensions (numLats, numLons)<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

!Write transposed values: map vector would be (/ 1, numLats /) <strong>for</strong><br />

! no transposition<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

The same effect can be obta<strong>in</strong>ed more simply us<strong>in</strong>g <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>tr<strong>in</strong>sic functions:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) :: rhValues<br />

! netCDF variable has dimensions (numLats, numLons)<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_put_var(ncid, rhVarId, transpose(rhValues))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)


Chapter 4: Variables 37<br />

4.7 Read<strong>in</strong>g Data Values: NF<strong>90</strong> GET VAR<br />

The function NF<strong>90</strong> GET VAR gets one or more data values from a netCDF variable of an<br />

open netCDF dataset that is <strong>in</strong> data mode. Required <strong>in</strong>puts are the netCDF ID, the variable<br />

ID, and a specification <strong>for</strong> the data values <strong>in</strong>to which the data will be read. Optional <strong>in</strong>puts<br />

may <strong>in</strong>dicate the start<strong>in</strong>g position of the data values <strong>in</strong> the netCDF variable (argument<br />

start), the sampl<strong>in</strong>g frequency with which data values are read from the netCDF variable<br />

(argument stride), and a mapp<strong>in</strong>g between the dimensions of the data array and the netCDF<br />

variable (argument map). The values to be read are associated with the netCDF variable<br />

by assum<strong>in</strong>g that the first dimension of the netCDF variable varies fastest <strong>in</strong> the <strong>Fortran</strong><br />

<strong>90</strong> <strong>in</strong>terface. Data values are converted from the external type of the variable, if necessary.<br />

Take care when us<strong>in</strong>g the simplest <strong>for</strong>ms of this <strong>in</strong>terface with record variables when you<br />

don’t specify how many records are to be read. If you try to read all the values of a record<br />

variable <strong>in</strong>to an array but there are more records <strong>in</strong> the file than you assume, more data<br />

will be read than you expect, which may cause a segmentation violation.<br />

Usage<br />

ncid<br />

varid<br />

values<br />

start<br />

count<br />

function nf<strong>90</strong>_get_var(ncid, varid, values, start, count, stride, map)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

any valid type, scalar or array of any rank, &<br />

<strong>in</strong>tent(out) :: values<br />

<strong>in</strong>teger, dimension(:), optional, <strong>in</strong>tent( <strong>in</strong>) :: start, count, stride, map<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_get_var<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID.<br />

The data value(s) to be read. The data may be of any type, and may be a<br />

scalar or an array of any rank. You cannot read CHARACTER data from a<br />

numeric variable or numeric data from a text variable. For numeric data, if the<br />

type of data differs from the netCDF variable type, type conversion will occur.<br />

See section “Type Conversion” <strong>in</strong> <strong>NetCDF</strong> Users Guide.<br />

A vector of <strong>in</strong>tegers specify<strong>in</strong>g the <strong>in</strong>dex <strong>in</strong> the variable from which the first<br />

(or only) of the data values will be read. The <strong>in</strong>dices are relative to 1, so <strong>for</strong><br />

example, the first data value of a variable would have <strong>in</strong>dex (1, 1, ..., 1). The<br />

elements of start correspond, <strong>in</strong> order, to the variable’s dimensions. Hence, if<br />

the variable is a record variable, the last <strong>in</strong>dex would correspond to the start<strong>in</strong>g<br />

record number <strong>for</strong> writ<strong>in</strong>g the data values.<br />

By default, start(:) = 1.<br />

A vector of <strong>in</strong>tegers specify<strong>in</strong>g the number of <strong>in</strong>dices selected along each dimension.<br />

To read a s<strong>in</strong>gle value, <strong>for</strong> example, specify count as (1, 1, ..., 1). The<br />

elements of count correspond, <strong>in</strong> order, to the variable’s dimensions. Hence,<br />

if the variable is a record variable, the last element of count corresponds to a<br />

count of the number of records to read.<br />

By default, count(:numDims) = shape(values) and count(numDims + 1:) = 1,<br />

where numDims = size(shape(values)).


38 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

stride<br />

map<br />

A vector of <strong>in</strong>tegers that specifies the sampl<strong>in</strong>g <strong>in</strong>terval along each dimension of<br />

the netCDF variable. The elements of the stride vector correspond, <strong>in</strong> order, to<br />

the netCDF variable’s dimensions (stride(1) gives the sampl<strong>in</strong>g <strong>in</strong>terval along<br />

the most rapidly vary<strong>in</strong>g dimension of the netCDF variable). Sampl<strong>in</strong>g <strong>in</strong>tervals<br />

are specified <strong>in</strong> type-<strong>in</strong>dependent units of elements (a value of 1 selects consecutive<br />

elements of the netCDF variable along the correspond<strong>in</strong>g dimension, a<br />

value of 2 selects every other element, etc.).<br />

By default, stride(:) = 1.<br />

A vector of <strong>in</strong>tegers that specifies the mapp<strong>in</strong>g between the dimensions of a<br />

netCDF variable and the <strong>in</strong>-memory structure of the <strong>in</strong>ternal data array. The<br />

elements of the <strong>in</strong>dex mapp<strong>in</strong>g vector correspond, <strong>in</strong> order, to the netCDF<br />

variable’s dimensions (map(1) gives the distance between elements of the <strong>in</strong>ternal<br />

array correspond<strong>in</strong>g to the most rapidly vary<strong>in</strong>g dimension of the netCDF<br />

variable). Distances between elements are specified <strong>in</strong> units of elements.<br />

By default, edgeLengths = shape(values), and map = (/ 1, (product(edgeLengths(:i)),<br />

i = 1, size(edgeLengths) - 1) /), that is, there is no<br />

mapp<strong>in</strong>g.<br />

Use of <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>tr<strong>in</strong>sic functions (<strong>in</strong>clud<strong>in</strong>g reshape, transpose, and spread)<br />

may let you avoid us<strong>in</strong>g this argument.<br />

Errors<br />

NF<strong>90</strong> GET VAR returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The assumed or specified start, count, and stride generate an <strong>in</strong>dex which is out of<br />

range. Note that no error check<strong>in</strong>g is possible on the map vector.<br />

• One or more of the specified values are out of the range of values representable by the<br />

desired type.<br />

• The specified netCDF is <strong>in</strong> def<strong>in</strong>e mode rather than data mode.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

(As noted above, another possible source of error is us<strong>in</strong>g this <strong>in</strong>terface to read all the<br />

values of a record variable without specify<strong>in</strong>g the number of records. If there are more<br />

records <strong>in</strong> the file than you assume, more data will be read than you expect!)<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> GET VAR to read the (4,3,2) element of the variable<br />

named rh from an exist<strong>in</strong>g netCDF dataset named foo.nc. For simplicity <strong>in</strong> this example,<br />

we assume that we know that rh is dimensioned with lon, lat, and time, so we want to read<br />

the value of rh that corresponds to the fourth lon value, the third lat value, and the second<br />

time value:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncId, rhVarId, status


Chapter 4: Variables 39<br />

real :: rhValue<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

-<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId, rhValue, start = (/ 4, 3, 2 /) )<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

In this example we use NF<strong>90</strong> GET VAR to read all the values of the variable named<br />

rh from an exist<strong>in</strong>g netCDF dataset named foo.nc. We assume that we know that rh is<br />

dimensioned with lon, lat, and time. In this example we query the netCDF file to discover<br />

the lengths of the dimensions, then allocate a <strong>Fortran</strong> <strong>90</strong> array the same shape as the<br />

netCDF variable.<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, &<br />

lonDimID, latDimId, timeDimId, &<br />

numLons, numLats, numTimes, &<br />

status<br />

<strong>in</strong>teger, dimension(nf<strong>90</strong>_max_var_dims) :: dimIDs<br />

real, dimension(:, :, :), allocatable :: rhValues<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

! How big is the netCDF variable, that is, what are the lengths of<br />

! its constituent dimensions?<br />

status = nf<strong>90</strong>_Inquire_Variable(ncid, rhVarId, dimids = dimIDs)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(1), len = numLons)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(2), len = numLats)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Dimension(ncid, dimIDs(3), len = numTimes)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

allocate(rhValues(numLons, numLats, numTimes))<br />

...<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId, rhValues)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> GET VAR to read a section of the variable named rh<br />

from an exist<strong>in</strong>g netCDF dataset named foo.nc. For simplicity <strong>in</strong> this example, we assume<br />

that we know that rh is dimensioned with lon, lat, and time, that there are ten lon values,


40 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

five lat values, and three time values, and that we want to replace all the values at the last<br />

time.<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 10, numLats = 5, numTimes = 3<br />

real, dimension(numLons, numLats, numTimes) &<br />

:: rhValues<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

!Read the values at the last time by pass<strong>in</strong>g an array section<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId, rhValues(:, :, 3), &<br />

start = (/ 1, 1, numTimes /), &<br />

count = (/ numLats, numLons, 1 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

Here is an example of us<strong>in</strong>g NF GET VAR to read every other po<strong>in</strong>t of a netCDF<br />

variable named rh hav<strong>in</strong>g dimensions (6, 4).<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) &<br />

:: rhValues<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

! Read every other value <strong>in</strong>to an array section<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId, rhValues(::2, ::2) &<br />

stride = (/ 2, 2 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

The follow<strong>in</strong>g map vector shows the default mapp<strong>in</strong>g between a 2x3x4 netCDF variable<br />

and an <strong>in</strong>ternal array of the same shape:<br />

real, dimension(2, 3, 4):: a ! same shape as netCDF variable<br />

<strong>in</strong>teger, dimension(3) :: map = (/ 1, 2, 6 /)<br />

! netCDF dimension <strong>in</strong>ter-element distance<br />

! ---------------- ----------------------<br />

! most rapidly vary<strong>in</strong>g 1<br />

! <strong>in</strong>termediate 2 (= map(1)*2)


Chapter 4: Variables 41<br />

! most slowly vary<strong>in</strong>g 6 (= map(2)*3)<br />

Us<strong>in</strong>g the map vector above obta<strong>in</strong>s the same result as simply not pass<strong>in</strong>g a map vector<br />

at all.<br />

Here is an example of us<strong>in</strong>g nf<strong>90</strong> get var to read a netCDF variable named rh whose<br />

dimensions are the transpose of the <strong>Fortran</strong> <strong>90</strong> array:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) :: rhValues<br />

! netCDF variable has dimensions (numLats, numLons)<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

! Read transposed values: map vector would be (/ 1, numLats /) <strong>for</strong><br />

! no transposition<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

The same effect can be obta<strong>in</strong>ed more simply, though us<strong>in</strong>g more memory, us<strong>in</strong>g <strong>Fortran</strong><br />

<strong>90</strong> <strong>in</strong>tr<strong>in</strong>sic functions:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncId, rhVarId, status<br />

<strong>in</strong>teger, parameter :: numLons = 6, numLats = 4<br />

real, dimension(numLons, numLats) :: rhValues<br />

! netCDF variable has dimensions (numLats, numLons)<br />

real, dimension(numLons, numLats) :: tempValues<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_NoWrite, ncid)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_get_var(ncid, rhVarId, tempValues))<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

rhValues(:, :) = transpose(tempValues)<br />

4.8 Read<strong>in</strong>g and Writ<strong>in</strong>g Character Str<strong>in</strong>g Values<br />

Character str<strong>in</strong>gs are not a primitive netCDF external data type, <strong>in</strong> part because FOR-<br />

TRAN does not support the abstraction of variable-length character str<strong>in</strong>gs (the FORTRAN


42 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

LEN function returns the static length of a character str<strong>in</strong>g, not its dynamic length). As<br />

a result, a character str<strong>in</strong>g cannot be written or read as a s<strong>in</strong>gle object <strong>in</strong> the netCDF<br />

<strong>in</strong>terface. Instead, a character str<strong>in</strong>g must be treated as an array of characters, and array<br />

access must be used to read and write character str<strong>in</strong>gs as variable data <strong>in</strong> netCDF datasets.<br />

Furthermore, variable-length str<strong>in</strong>gs are not supported by the netCDF <strong>in</strong>terface except by<br />

convention; <strong>for</strong> example, you may treat a zero byte as term<strong>in</strong>at<strong>in</strong>g a character str<strong>in</strong>g, but<br />

you must explicitly specify the length of str<strong>in</strong>gs to be read from and written to netCDF<br />

variables.<br />

Character str<strong>in</strong>gs as attribute values are easier to use, s<strong>in</strong>ce the str<strong>in</strong>gs are treated as a<br />

s<strong>in</strong>gle unit <strong>for</strong> access. However, the value of a character-str<strong>in</strong>g attribute is still an array of<br />

characters with an explicit length that must be specified when the attribute is def<strong>in</strong>ed.<br />

When you def<strong>in</strong>e a variable that will have character-str<strong>in</strong>g values, use a character-position<br />

dimension as the most quickly vary<strong>in</strong>g dimension <strong>for</strong> the variable (the first dimension <strong>for</strong><br />

the variable <strong>in</strong> <strong>Fortran</strong> <strong>90</strong>). The length of the character-position dimension will be the<br />

maximum str<strong>in</strong>g length of any value to be stored <strong>in</strong> the character-str<strong>in</strong>g variable. Space<br />

<strong>for</strong> maximum-length str<strong>in</strong>gs will be allocated <strong>in</strong> the disk representation of character-str<strong>in</strong>g<br />

variables whether you use the space or not. If two or more variables have the same maximum<br />

length, the same character-position dimension may be used <strong>in</strong> def<strong>in</strong><strong>in</strong>g the variable shapes.<br />

To write a character-str<strong>in</strong>g value <strong>in</strong>to a character-str<strong>in</strong>g variable, use either entire variable<br />

access or array access. The latter requires that you specify both a corner and a vector<br />

of edge lengths. The character-position dimension at the corner should be one <strong>for</strong> <strong>Fortran</strong><br />

<strong>90</strong>. If the length of the str<strong>in</strong>g to be written is n, then the vector of edge lengths will specify<br />

n <strong>in</strong> the character-position dimension, and one <strong>for</strong> all the other dimensions: (n, 1, 1, ..., 1).<br />

In <strong>Fortran</strong> <strong>90</strong>, fixed-length str<strong>in</strong>gs may be written to a netCDF dataset without a term<strong>in</strong>at<strong>in</strong>g<br />

character, to save space. Variable-length str<strong>in</strong>gs should follow the C convention<br />

of writ<strong>in</strong>g str<strong>in</strong>gs with a term<strong>in</strong>at<strong>in</strong>g zero byte so that the <strong>in</strong>tended length of the str<strong>in</strong>g can<br />

be determ<strong>in</strong>ed when it is later read by either C or <strong>Fortran</strong> <strong>90</strong> programs.<br />

4.9 Fill Values<br />

What happens when you try to read a value that was never written <strong>in</strong> an open netCDF<br />

dataset? You might expect that this should always be an error, and that you should get an<br />

error message or an error status returned. You do get an error if you try to read data from<br />

a netCDF dataset that is not open <strong>for</strong> read<strong>in</strong>g, if the variable ID is <strong>in</strong>valid <strong>for</strong> the specified<br />

netCDF dataset, or if the specified <strong>in</strong>dices are not properly with<strong>in</strong> the range def<strong>in</strong>ed by the<br />

dimension lengths of the specified variable. Otherwise, read<strong>in</strong>g a value that was not written<br />

returns a special fill value used to fill <strong>in</strong> any undef<strong>in</strong>ed values when a netCDF variable is<br />

first written.<br />

You may ignore fill values and use the entire range of a netCDF external data type, but<br />

<strong>in</strong> this case you should make sure you write all data values be<strong>for</strong>e read<strong>in</strong>g them. If you<br />

know you will be writ<strong>in</strong>g all the data be<strong>for</strong>e read<strong>in</strong>g it, you can specify that no prefill<strong>in</strong>g<br />

of variables with fill values will occur by call<strong>in</strong>g writ<strong>in</strong>g. This may provide a significant<br />

per<strong>for</strong>mance ga<strong>in</strong> <strong>for</strong> netCDF writes.<br />

The variable attribute FillValue may be used to specify the fill value <strong>for</strong> a<br />

variable. There are default fill values <strong>for</strong> each type, def<strong>in</strong>ed <strong>in</strong> module netcdf:<br />

NF<strong>90</strong> FILL CHAR, NF<strong>90</strong> FILL INT1 (same as NF<strong>90</strong> FILL BYTE), NF<strong>90</strong> FILL INT2


Chapter 4: Variables 43<br />

(same as NF<strong>90</strong> FILL SHORT), NF<strong>90</strong> FILL INT, NF<strong>90</strong> FILL REAL (same as<br />

NF<strong>90</strong> FILL FLOAT), and NF<strong>90</strong> FILL DOUBLE<br />

The netCDF byte and character types have different default fill values. The default fill<br />

value <strong>for</strong> characters is the zero byte, a useful value <strong>for</strong> detect<strong>in</strong>g the end of variable-length<br />

C character str<strong>in</strong>gs. If you need a fill value <strong>for</strong> a byte variable, it is recommended that you<br />

explicitly def<strong>in</strong>e an appropriate FillValue attribute, as generic utilities such as ncdump will<br />

not assume a default fill value <strong>for</strong> byte variables.<br />

Type conversion <strong>for</strong> fill values is identical to type conversion <strong>for</strong> other values: attempt<strong>in</strong>g<br />

to convert a value from one type to another type that can’t represent the value results <strong>in</strong><br />

a range error. Such errors may occur on writ<strong>in</strong>g or read<strong>in</strong>g values from a larger type (such<br />

as double) to a smaller type (such as float), if the fill value <strong>for</strong> the larger type cannot be<br />

represented <strong>in</strong> the smaller type.<br />

4.10 NF<strong>90</strong> RENAME VAR<br />

The function NF<strong>90</strong> RENAME VAR changes the name of a netCDF variable <strong>in</strong> an open<br />

netCDF dataset. If the new name is longer than the old name, the netCDF dataset must<br />

be <strong>in</strong> def<strong>in</strong>e mode. You cannot rename a variable to have the name of any exist<strong>in</strong>g variable.<br />

Usage<br />

ncid<br />

varid<br />

newname<br />

Errors<br />

function nf<strong>90</strong>_rename_var(ncid, varid, newname)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: newname<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_var<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID.<br />

New name <strong>for</strong> the specified variable.<br />

NF<strong>90</strong> RENAME VAR returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The new name is <strong>in</strong> use as the name of another variable.<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> RENAME VAR to rename the variable rh to rel hum <strong>in</strong><br />

an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncId, rhVarId, status<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_Write, ncid)


44 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", rhVarId)<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_redef(ncid) ! Enter def<strong>in</strong>e mode to change variable name<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_rename_var(ncid, rhVarId, "rel_hum")<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)<br />

status = nf<strong>90</strong>_enddef(ncid) ! Leave def<strong>in</strong>e mode<br />

if(status /= nf<strong>90</strong>_NoErr) call handle_err(status)


Chapter 5: Attributes 45<br />

5 Attributes<br />

5.1 Attributes Introduction<br />

Attributes may be associated with each netCDF variable to specify such properties as units,<br />

special values, maximum and m<strong>in</strong>imum valid values, scal<strong>in</strong>g factors, and offsets. Attributes<br />

<strong>for</strong> a netCDF dataset are def<strong>in</strong>ed when the dataset is first created, while the netCDF dataset<br />

is <strong>in</strong> def<strong>in</strong>e mode. Additional attributes may be added later by reenter<strong>in</strong>g def<strong>in</strong>e mode. A<br />

netCDF attribute has a netCDF variable to which it is assigned, a name, a type, a length,<br />

and a sequence of one or more values. An attribute is designated by its variable ID and<br />

name. When an attribute name is not known, it may be designated by its variable ID and<br />

number <strong>in</strong> order to determ<strong>in</strong>e its name, us<strong>in</strong>g the function NF<strong>90</strong> INQ ATTNAME.<br />

The attributes associated with a variable are typically def<strong>in</strong>ed immediately after the<br />

variable is created, while still <strong>in</strong> def<strong>in</strong>e mode. The data type, length, and value of an<br />

attribute may be changed even when <strong>in</strong> data mode, as long as the changed attribute requires<br />

no more space than the attribute as orig<strong>in</strong>ally def<strong>in</strong>ed.<br />

It is also possible to have attributes that are not associated with any variable. These are<br />

called global attributes and are identified by us<strong>in</strong>g NF<strong>90</strong> GLOBAL as a variable pseudo-ID.<br />

Global attributes are usually related to the netCDF dataset as a whole and may be used<br />

<strong>for</strong> purposes such as provid<strong>in</strong>g a title or process<strong>in</strong>g history <strong>for</strong> a netCDF dataset.<br />

Operations supported on attributes are:<br />

• Create an attribute, given its variable ID, name, data type, length, and value.<br />

• Get attribute’s data type and length from its variable ID and name.<br />

• Get attribute’s value from its variable ID and name.<br />

• Copy attribute from one netCDF variable to another.<br />

• Get name of attribute from its number.<br />

• Rename an attribute.<br />

• Delete an attribute.<br />

5.2 Attribute Conventions<br />

Names commenc<strong>in</strong>g with underscore (’ ’) are reserved <strong>for</strong> use by the netCDF library. Most<br />

generic applications that process netCDF datasets assume standard attribute conventions<br />

and it is strongly recommended that these be followed unless there are good reasons <strong>for</strong> not<br />

do<strong>in</strong>g so. Below we list the names and mean<strong>in</strong>gs of recommended standard attributes that<br />

have proven useful. Note that some of these (e.g. units, valid range, scale factor) assume<br />

numeric data and should not be used with character data. units<br />

A character str<strong>in</strong>g that specifies the units used <strong>for</strong> the variable’s data. <strong>Unidata</strong> has<br />

developed a freely-available library of rout<strong>in</strong>es to convert between character str<strong>in</strong>g and<br />

b<strong>in</strong>ary <strong>for</strong>ms of unit specifications and to per<strong>for</strong>m various useful operations on the b<strong>in</strong>ary<br />

<strong>for</strong>ms. This library is used <strong>in</strong> some netCDF applications. Us<strong>in</strong>g the recommended units<br />

syntax permits data represented <strong>in</strong> con<strong>for</strong>mable units to be automatically converted to<br />

common units <strong>for</strong> arithmetic operations. See section “Appendix A - Units” <strong>in</strong> The <strong>NetCDF</strong><br />

Users’ Guide.


46 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

long_name<br />

valid_m<strong>in</strong><br />

valid_max<br />

A long descriptive name. This could be used <strong>for</strong> label<strong>in</strong>g plots, <strong>for</strong> example. If<br />

a variable has no long name attribute assigned, the variable name should be<br />

used as a default.<br />

A scalar specify<strong>in</strong>g the m<strong>in</strong>imum valid value <strong>for</strong> this variable.<br />

A scalar specify<strong>in</strong>g the maximum valid value <strong>for</strong> this variable.<br />

valid_range<br />

A vector of two numbers specify<strong>in</strong>g the m<strong>in</strong>imum and maximum valid values<br />

<strong>for</strong> this variable, equivalent to specify<strong>in</strong>g values <strong>for</strong> both valid m<strong>in</strong> and<br />

valid max attributes. Any of these attributes def<strong>in</strong>e the valid range. The<br />

attribute valid range must not be def<strong>in</strong>ed if either valid m<strong>in</strong> or valid max is<br />

def<strong>in</strong>ed.<br />

Generic applications should treat values outside the valid range as miss<strong>in</strong>g. The<br />

type of each valid range, valid m<strong>in</strong> and valid max attribute should match the<br />

type of its variable (except that <strong>for</strong> byte data, these can be of a signed <strong>in</strong>tegral<br />

type to specify the <strong>in</strong>tended range).<br />

If neither valid m<strong>in</strong>, valid max nor valid range is def<strong>in</strong>ed then generic applications<br />

should def<strong>in</strong>e a valid range as follows. If the data type is byte and<br />

FillValue is not explicitly def<strong>in</strong>ed, then the valid range should <strong>in</strong>clude all possible<br />

values. Otherwise, the valid range should exclude the FillValue (whether<br />

def<strong>in</strong>ed explicitly or by default) as follows. If the FillValue is positive then<br />

it def<strong>in</strong>es a valid maximum, otherwise it def<strong>in</strong>es a valid m<strong>in</strong>imum. For <strong>in</strong>teger<br />

types, there should be a difference of 1 between the FillValue and this valid<br />

m<strong>in</strong>imum or maximum. For float<strong>in</strong>g po<strong>in</strong>t types, the difference should be twice<br />

the m<strong>in</strong>imum possible (1 <strong>in</strong> the least significant bit) to allow <strong>for</strong> round<strong>in</strong>g error.<br />

scale_factor<br />

If present <strong>for</strong> a variable, the data are to be multiplied by this factor after the<br />

data are read by the application that accesses the data.<br />

add_offset<br />

If present <strong>for</strong> a variable, this number is to be added to the data after it is read<br />

by the application that accesses the data. If both scale factor and add offset<br />

attributes are present, the data are first scaled be<strong>for</strong>e the offset is added. The<br />

attributes scale factor and add offset can be used together to provide simple<br />

data compression to store low-resolution float<strong>in</strong>g-po<strong>in</strong>t data as small <strong>in</strong>tegers <strong>in</strong><br />

a netCDF dataset. When scaled data are written, the application should first<br />

subtract the offset and then divide by the scale factor.<br />

When scale factor and add offset are used <strong>for</strong> pack<strong>in</strong>g, the associated variable<br />

(conta<strong>in</strong><strong>in</strong>g the packed data) is typically of type byte or short, whereas the<br />

unpacked values are <strong>in</strong>tended to be of type float or double. The attributes<br />

scale factor and add offset should both be of the type <strong>in</strong>tended <strong>for</strong> the unpacked<br />

data, e.g. float or double.


Chapter 5: Attributes 47<br />

_FillValue<br />

The FillValue attribute specifies the fill value used to pre-fill disk space allocated<br />

to the variable. Such pre-fill occurs unless nofill mode is set us<strong>in</strong>g<br />

NF<strong>90</strong> SET FILL. See Section 2.13 [NF<strong>90</strong> SET FILL], page 19. The fill value<br />

is returned when read<strong>in</strong>g values that were never written. If FillValue is def<strong>in</strong>ed<br />

then it should be scalar and of the same type as the variable. It is not<br />

necessary to def<strong>in</strong>e your own FillValue attribute <strong>for</strong> a variable if the default<br />

fill value <strong>for</strong> the type of the variable is adequate. However, use of the default<br />

fill value <strong>for</strong> data type byte is not recommended. Note that if you change the<br />

value of this attribute, the changed value applies only to subsequent writes;<br />

previously written data are not changed.<br />

Generic applications often need to write a value to represent undef<strong>in</strong>ed or miss<strong>in</strong>g<br />

values. The fill value provides an appropriate value <strong>for</strong> this purpose because<br />

it is normally outside the valid range and there<strong>for</strong>e treated as miss<strong>in</strong>g when read<br />

by generic applications. It is legal (but not recommended) <strong>for</strong> the fill value to<br />

be with<strong>in</strong> the valid range.<br />

See Section 4.9 [Fill Values], page 42.<br />

miss<strong>in</strong>g_value<br />

This attribute is not treated <strong>in</strong> any special way by the library or con<strong>for</strong>m<strong>in</strong>g<br />

generic applications, but is often useful documentation and may be used by<br />

specific applications. The miss<strong>in</strong>g value attribute can be a scalar or vector<br />

conta<strong>in</strong><strong>in</strong>g values <strong>in</strong>dicat<strong>in</strong>g miss<strong>in</strong>g data. These values should all be outside<br />

the valid range so that generic applications will treat them as miss<strong>in</strong>g.<br />

signedness<br />

Deprecated attribute, orig<strong>in</strong>ally designed to <strong>in</strong>dicate whether byte values should<br />

be treated as signed or unsigned. The attributes valid m<strong>in</strong> and valid max may<br />

be used <strong>for</strong> this purpose. For example, if you <strong>in</strong>tend that a byte variable store<br />

only nonnegative values, you can use valid m<strong>in</strong> = 0 and valid max = 255. This<br />

attribute is ignored by the netCDF library.<br />

C_<strong>for</strong>mat<br />

A character array provid<strong>in</strong>g the <strong>for</strong>mat that should be used by C applications<br />

to pr<strong>in</strong>t values <strong>for</strong> this variable. For example, if you know a variable is only accurate<br />

to three significant digits, it would be appropriate to def<strong>in</strong>e the C <strong>for</strong>mat<br />

attribute as "%.3g". The ncdump utility program uses this attribute <strong>for</strong> variables<br />

<strong>for</strong> which it is def<strong>in</strong>ed. The <strong>for</strong>mat applies to the scaled (<strong>in</strong>ternal) type<br />

and value, regardless of the presence of the scal<strong>in</strong>g attributes scale factor and<br />

add offset.<br />

FORTRAN_<strong>for</strong>mat<br />

A character array provid<strong>in</strong>g the <strong>for</strong>mat that should be used by FORTRAN<br />

applications to pr<strong>in</strong>t values <strong>for</strong> this variable. For example, if you know a variable<br />

is only accurate to three significant digits, it would be appropriate to def<strong>in</strong>e the<br />

FORTRAN <strong>for</strong>mat attribute as "(G10.3)".<br />

title<br />

A global attribute that is a character array provid<strong>in</strong>g a succ<strong>in</strong>ct description of<br />

what is <strong>in</strong> the dataset.


48 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

history A global attribute <strong>for</strong> an audit trail. This is a character array with a l<strong>in</strong>e<br />

<strong>for</strong> each <strong>in</strong>vocation of a program that has modified the dataset. Well-behaved<br />

generic netCDF applications should append a l<strong>in</strong>e conta<strong>in</strong><strong>in</strong>g: date, time of<br />

day, user name, program name and command arguments.<br />

Conventions<br />

If present, ’Conventions’ is a global attribute that is a character array <strong>for</strong> the<br />

name of the conventions followed by the dataset, <strong>in</strong> the <strong>for</strong>m of a str<strong>in</strong>g that<br />

is <strong>in</strong>terpreted as a directory name relative to a directory that is a repository of<br />

documents describ<strong>in</strong>g sets of discipl<strong>in</strong>e-specific conventions. This permits a hierarchical<br />

structure <strong>for</strong> conventions and provides a place where descriptions and<br />

examples of the conventions may be ma<strong>in</strong>ta<strong>in</strong>ed by the def<strong>in</strong><strong>in</strong>g <strong>in</strong>stitutions and<br />

groups. The conventions directory name is currently <strong>in</strong>terpreted relative to the<br />

directory pub/netcdf/Conventions/ on the host mach<strong>in</strong>e ftp.unidata.ucar.edu.<br />

Alternatively, a full URL specification may be used to name a WWW site where<br />

documents that describe the conventions are ma<strong>in</strong>ta<strong>in</strong>ed.<br />

For example, if a group named NUWG agrees upon a set of conventions <strong>for</strong><br />

dimension names, variable names, required attributes, and netCDF representations<br />

<strong>for</strong> certa<strong>in</strong> discipl<strong>in</strong>e-specific data structures, they may store a document<br />

describ<strong>in</strong>g the agreed-upon conventions <strong>in</strong> a dataset <strong>in</strong> the NUWG/ subdirectory<br />

of the Conventions directory. Datasets that followed these conventions<br />

would conta<strong>in</strong> a global Conventions attribute with value "NUWG".<br />

Later, if the group agrees upon some additional conventions <strong>for</strong> a specific subset<br />

of NUWG data, <strong>for</strong> example time series data, the description of the additional<br />

conventions might be stored <strong>in</strong> the NUWG/Time series/ subdirectory,<br />

and datasets that adhered to these additional conventions would use the global<br />

Conventions attribute with value "NUWG/Time series", imply<strong>in</strong>g that this<br />

dataset adheres to the NUWG conventions and also to the additional NUWG<br />

time-series conventions.<br />

5.3 Create an Attribute: NF<strong>90</strong> PUT ATT<br />

The function NF<strong>90</strong> PUT ATTadds or changes a variable attribute or global attribute of an<br />

open netCDF dataset. If this attribute is new, or if the space required to store the attribute<br />

is greater than be<strong>for</strong>e, the netCDF dataset must be <strong>in</strong> def<strong>in</strong>e mode.<br />

Usage<br />

Although it’s possible to create attributes of all types, text and double attributes are adequate<br />

<strong>for</strong> most purposes.<br />

ncid<br />

function nf<strong>90</strong>_put_att(ncid, varid, name, values)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character(len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

any valid type, scalar or array of rank 1, &<br />

<strong>in</strong>tent( <strong>in</strong>) :: values<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_put_att<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.


Chapter 5: Attributes 49<br />

varid<br />

name<br />

values<br />

Variable ID of the variable to which the attribute will be assigned or<br />

NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute.<br />

Attribute name. Must beg<strong>in</strong> with an alphabetic character, followed by zero or<br />

more alphanumeric characters <strong>in</strong>clud<strong>in</strong>g the underscore (’ ’). Case is significant.<br />

Attribute name conventions are assumed by some netCDF generic applications,<br />

e.g., units as the name <strong>for</strong> a str<strong>in</strong>g attribute that gives the units <strong>for</strong> a netCDF<br />

variable. For examples of attribute conventions Section 5.2 [Attribute Conventions],<br />

page 45.<br />

An array of attribute values. Values may be supplied as scalars or as arrays of<br />

rank one (one dimensional vectors). The external data type of the attribute is<br />

set to match the <strong>in</strong>ternal representation of the argument, that is if values is a<br />

two byte <strong>in</strong>teger array, the attribute will be of type NF<strong>90</strong> INT2. <strong>Fortran</strong> <strong>90</strong><br />

<strong>in</strong>tr<strong>in</strong>sic functions can be used to convert attributes to the desired type.<br />

Errors<br />

NF<strong>90</strong> PUT ATT returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified netCDF type is <strong>in</strong>valid.<br />

• The specified length is negative.<br />

• The specified open netCDF dataset is <strong>in</strong> data mode and the specified attribute would<br />

expand.<br />

• The specified open netCDF dataset is <strong>in</strong> data mode and the specified attribute does<br />

not already exist.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

• The number of attributes <strong>for</strong> this variable exceeds NF<strong>90</strong> MAX ATTRS.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> PUT ATT to add a variable attribute named valid range<br />

<strong>for</strong> a netCDF variable named rh and a global attribute named title to an exist<strong>in</strong>g netCDF<br />

dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status, RHVarID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_write, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! Enter def<strong>in</strong>e mode so we can add the attribute<br />

status = nf<strong>90</strong>_redef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Get the variable ID <strong>for</strong> "rh"...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RHVarID)


50 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! ... put the range attribute, sett<strong>in</strong>g it to eight byte reals...<br />

status = nf<strong>90</strong>_put_att(ncid, RHVarID, "valid_range", real((/ 0, 100 /))<br />

! ... and the title attribute.<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_put_att(ncid, RHVarID, "title", "example netCDF dataset") )<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Leave def<strong>in</strong>e mode<br />

status = nf<strong>90</strong>_enddef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

5.4 Get In<strong>for</strong>mation about an Attribute: NF<strong>90</strong> Inquire Att<br />

and NF<strong>90</strong> INQ ATTNAME<br />

The function NF<strong>90</strong> Inquire att returns <strong>in</strong><strong>for</strong>mation about a netCDF attribute given the<br />

variable ID and attribute name. In<strong>for</strong>mation about an attribute <strong>in</strong>cludes its type, length,<br />

name, and number. See NF<strong>90</strong> GET ATT <strong>for</strong> gett<strong>in</strong>g attribute values.<br />

The function NF<strong>90</strong> INQ ATTNAME gets the name of an attribute, given its variable<br />

ID and number. This function is useful <strong>in</strong> generic applications that need to get the names<br />

of all the attributes associated with a variable, s<strong>in</strong>ce attributes are accessed by name rather<br />

than number <strong>in</strong> all other attribute functions. The number of an attribute is more volatile<br />

than the name, s<strong>in</strong>ce it can change when other attributes of the same variable are deleted.<br />

This is why an attribute number is not called an attribute ID.<br />

Usage<br />

function nf<strong>90</strong>_Inquire_Attribute(ncid, varid, name, xtype, len, attnum)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>)<br />

:: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out), optional :: xtype, len, attnum<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Attribute<br />

function nf<strong>90</strong>_<strong>in</strong>q_attname(ncid, varid, attnum, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid, attnum<br />

character (len = *), <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_attname<br />

ncid<br />

varid<br />

name<br />

xtype<br />

len<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID of the attribute’s variable, or NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute.<br />

Attribute name. For NF<strong>90</strong> INQ ATTNAME, this is a po<strong>in</strong>ter to the location<br />

<strong>for</strong> the returned attribute name.<br />

Returned attribute type, one of the set of predef<strong>in</strong>ed netCDF external data<br />

types. The valid netCDF external data types are NF<strong>90</strong> BYTE, NF<strong>90</strong> CHAR,<br />

NF<strong>90</strong> SHORT, NF<strong>90</strong> INT, NF<strong>90</strong> FLOAT, and NF<strong>90</strong> DOUBLE.<br />

Returned number of values currently stored <strong>in</strong> the attribute. For a str<strong>in</strong>g-valued<br />

attribute, this is the number of characters <strong>in</strong> the str<strong>in</strong>g.


Chapter 5: Attributes 51<br />

attnum For NF<strong>90</strong> INQ ATTNAME, the <strong>in</strong>put attribute number; <strong>for</strong><br />

NF<strong>90</strong> INQ ATTID, the returned attribute number. The attributes<br />

<strong>for</strong> each variable are numbered from 1 (the first attribute) to NATTS, where<br />

NATTS is the number of attributes <strong>for</strong> the variable, as returned from a call to<br />

NF<strong>90</strong> INQ VARNATTS.<br />

Errors<br />

(If you already know an attribute name, know<strong>in</strong>g its number is not very useful,<br />

because access<strong>in</strong>g <strong>in</strong><strong>for</strong>mation about an attribute requires its name.)<br />

Each function returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the returned<br />

status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified attribute does not exist.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

• For NF<strong>90</strong> INQ ATTNAME, the specified attribute number is negative or more than<br />

the number of attributes def<strong>in</strong>ed <strong>for</strong> the specified variable.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> Inquire Att to <strong>in</strong>quire about the lengths of an attribute<br />

named valid range <strong>for</strong> a netCDF variable named rh and a global attribute named title <strong>in</strong><br />

an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid, status<br />

<strong>in</strong>teger :: RHVarID<br />

! Variable ID<br />

<strong>in</strong>teger :: validRangeLength, titleLength ! Attribute lengths<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! Get the variable ID <strong>for</strong> "rh"...<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! ... get the length of the "valid_range" attribute...<br />

status = nf<strong>90</strong>_Inquire_Att(ncid, RHVarID, "valid_range", &<br />

len = validRangeLength)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! ... and the global title attribute.<br />

status = nf<strong>90</strong>_Inquire_Att(ncid, nf<strong>90</strong>_global, "title", len = titleLength)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

5.5 Get Attribute’s Values: NF<strong>90</strong> GET ATT<br />

Function nf<strong>90</strong> get att gets the value(s) of a netCDF attribute, given its variable ID and<br />

name.


52 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Usage<br />

ncid<br />

varid<br />

name<br />

values<br />

Errors<br />

function nf<strong>90</strong>_get_att(ncid, varid, name, values)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character(len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

any valid type, scalar or array of rank 1, &<br />

<strong>in</strong>tent(out) :: values<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_get_att<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

Variable ID of the attribute’s variable, or NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute.<br />

Attribute name.<br />

Returned attribute values. All elements of the vector of attribute values are<br />

returned, so you must provide enough space to hold them. If you don’t know<br />

how much space to reserve, call NF<strong>90</strong> Inquire Att first to f<strong>in</strong>d out the length<br />

of the attribute. If there is only a s<strong>in</strong>gle attribute values may be a scalar. If<br />

the attribute is of type character values should be a variable of type character<br />

with the len <strong>Fortran</strong> <strong>90</strong> attribute set to an appropriate value (i.e. character (len<br />

= 80) :: values). You cannot read character data from a numeric variable or<br />

numeric data from a text variable. For numeric data, if the type of data differs<br />

from the netCDF variable type, type conversion will occur. See section “Type<br />

Conversion” <strong>in</strong> <strong>NetCDF</strong> Users Guide.<br />

NF<strong>90</strong> GET ATT type returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified attribute does not exist.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

• One or more of the attribute values are out of the range of values representable by the<br />

desired type.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> GET ATT to determ<strong>in</strong>e the values of an attribute named<br />

valid range <strong>for</strong> a netCDF variable named rh and a global attribute named title <strong>in</strong> an exist<strong>in</strong>g<br />

netCDF dataset named foo.nc. In this example, it is assumed that we don’t know how many<br />

values will be returned, so we first <strong>in</strong>quire about the length of the attributes to make sure<br />

we have enough space to store them:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger<br />

:: ncid, status<br />

<strong>in</strong>teger :: RHVarID ! Variable ID<br />

<strong>in</strong>teger<br />

:: validRangeLength, titleLength ! Attribute lengths<br />

real, dimension(:), allocatable, &


Chapter 5: Attributes 53<br />

:: validRange<br />

character (len = 80) :: title<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! F<strong>in</strong>d the lengths of the attributes<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Att(ncid, RHVarID, "valid_range", &<br />

len = validRangeLength)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_Inquire_Att(ncid, nf<strong>90</strong>_global, "title", len = titleLength)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

!Allocate space to hold attribute values, check str<strong>in</strong>g lengths<br />

allocate(validRange(validRangeLength), stat = status)<br />

if(status /= 0 .or. len(title) < titleLength)<br />

pr<strong>in</strong>t *, "Not enough space to put attribute values."<br />

exit<br />

end if<br />

! Read the attributes.<br />

status = nf<strong>90</strong>_get_att(ncid, RHVarID, "valid_range", validRange)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_get_att(ncid, nf<strong>90</strong>_global, "title", title)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

5.6 Copy Attribute from One <strong>NetCDF</strong> to Another:<br />

NF<strong>90</strong> COPY ATT<br />

The function NF<strong>90</strong> COPY ATT copies an attribute from one open netCDF dataset to<br />

another. It can also be used to copy an attribute from one variable to another with<strong>in</strong> the<br />

same netCDF dataset.<br />

Usage<br />

ncid_<strong>in</strong><br />

varid_<strong>in</strong><br />

name<br />

function nf<strong>90</strong>_copy_att(ncid_<strong>in</strong>, varid_<strong>in</strong>, name, ncid_out, varid_out)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid_<strong>in</strong>, varid_<strong>in</strong><br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid_out, varid_out<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_copy_att<br />

The netCDF ID of an <strong>in</strong>put netCDF dataset from which the attribute will be<br />

copied, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

ID of the variable <strong>in</strong> the <strong>in</strong>put netCDF dataset from which the attribute will<br />

be copied, or NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute.<br />

Name of the attribute <strong>in</strong> the <strong>in</strong>put netCDF dataset to be copied.


54 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

ncid_out<br />

varid_out<br />

The netCDF ID of the output netCDF dataset to which the attribute will be<br />

copied, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE. It is permissible<br />

<strong>for</strong> the <strong>in</strong>put and output netCDF IDs to be the same. The output netCDF<br />

dataset should be <strong>in</strong> def<strong>in</strong>e mode if the attribute to be copied does not already<br />

exist <strong>for</strong> the target variable, or if it would cause an exist<strong>in</strong>g target attribute to<br />

grow.<br />

ID of the variable <strong>in</strong> the output netCDF dataset to which the attribute will be<br />

copied, or NF<strong>90</strong> GLOBAL to copy to a global attribute.<br />

Errors<br />

NF<strong>90</strong> COPY ATT returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The <strong>in</strong>put or output variable ID is <strong>in</strong>valid <strong>for</strong> the specified netCDF dataset.<br />

• The specified attribute does not exist.<br />

• The output netCDF is not <strong>in</strong> def<strong>in</strong>e mode and the attribute is new <strong>for</strong> the output<br />

dataset is larger than the exist<strong>in</strong>g attribute.<br />

• The <strong>in</strong>put or output netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> COPY ATT to copy the variable attribute units from the<br />

variable rh <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc to the variable avgrh <strong>in</strong> another<br />

exist<strong>in</strong>g netCDF dataset named bar.nc, assum<strong>in</strong>g that the variable avgrh already exists,<br />

but does not yet have a units attribute:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid1, ncid2, status<br />

<strong>in</strong>teger :: RHVarID, avgRHVarID ! Variable ID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid1)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_open("bar.nc", nf<strong>90</strong>_write, ncid2)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! F<strong>in</strong>d the IDs of the variables<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid1, "rh", RHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid1, "avgrh", avgRHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_redef(ncid2) ! Enter def<strong>in</strong>e mode<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

! Copy variable attribute from "rh" <strong>in</strong> file 1 to "avgrh" <strong>in</strong> file 1<br />

status = nf<strong>90</strong>_copy_att(ncid1, RHVarID, "units", ncid2, avgRHVarID)


Chapter 5: Attributes 55<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_enddef(ncid2)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

5.7 Rename an Attribute: NF<strong>90</strong> RENAME ATT<br />

The function NF<strong>90</strong> RENAME ATT changes the name of an attribute. If the new name is<br />

longer than the orig<strong>in</strong>al name, the netCDF dataset must be <strong>in</strong> def<strong>in</strong>e mode. You cannot<br />

rename an attribute to have the same name as another attribute of the same variable.<br />

Usage<br />

ncid<br />

varid<br />

curname<br />

newname<br />

Errors<br />

function nf<strong>90</strong>_rename_att(ncid, varid, curname, newname)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: curname, newname<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_att<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE<br />

ID of the attribute’s variable, or NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute<br />

The current attribute name.<br />

The new name to be assigned to the specified attribute. If the new name is<br />

longer than the current name, the netCDF dataset must be <strong>in</strong> def<strong>in</strong>e mode.<br />

NF<strong>90</strong> RENAME ATT returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise,<br />

the returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified variable ID is not valid.<br />

• The new attribute name is already <strong>in</strong> use <strong>for</strong> another attribute of the specified variable.<br />

• The specified netCDF dataset is <strong>in</strong> data mode and the new name is longer than the<br />

old name.<br />

• The specified attribute does not exist.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> RENAME ATT to rename the variable attribute units to<br />

Units <strong>for</strong> a variable rh <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid1, status<br />

<strong>in</strong>teger :: RHVarID ! Variable ID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...


56 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

! F<strong>in</strong>d the IDs of the variables<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

status = nf<strong>90</strong>_rename_att(ncid, RHVarID, "units", "Units")<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

5.8 NF<strong>90</strong> DEL ATT<br />

The function NF<strong>90</strong> DEL ATT deletes a netCDF attribute from an open netCDF dataset.<br />

The netCDF dataset must be <strong>in</strong> def<strong>in</strong>e mode.<br />

Usage<br />

ncid<br />

varid<br />

name<br />

Errors<br />

function nf<strong>90</strong>_del_att(ncid, varid, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_del_att<br />

<strong>NetCDF</strong> ID, from a previous call to NF<strong>90</strong> OPEN or NF<strong>90</strong> CREATE.<br />

ID of the attribute’s variable, or NF<strong>90</strong> GLOBAL <strong>for</strong> a global attribute.<br />

The name of the attribute to be deleted.<br />

NF<strong>90</strong> DEL ATT returns the value NF<strong>90</strong> NOERR if no errors occurred. Otherwise, the<br />

returned status <strong>in</strong>dicates an error. Possible causes of errors <strong>in</strong>clude:<br />

• The specified variable ID is not valid.<br />

• The specified netCDF dataset is <strong>in</strong> data mode.<br />

• The specified attribute does not exist.<br />

• The specified netCDF ID does not refer to an open netCDF dataset.<br />

Example<br />

Here is an example us<strong>in</strong>g NF<strong>90</strong> DEL ATT to delete the variable attribute Units <strong>for</strong> a<br />

variable rh <strong>in</strong> an exist<strong>in</strong>g netCDF dataset named foo.nc:<br />

use netcdf<br />

implicit none<br />

<strong>in</strong>teger :: ncid1, status<br />

<strong>in</strong>teger :: RHVarID ! Variable ID<br />

...<br />

status = nf<strong>90</strong>_open("foo.nc", nf<strong>90</strong>_nowrite, ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

...<br />

! F<strong>in</strong>d the IDs of the variables<br />

status = nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, "rh", RHVarID)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)


Chapter 5: Attributes 57<br />

...<br />

status = nf<strong>90</strong>_redef(ncid) ! Enter def<strong>in</strong>e mode<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_del_att(ncid, RHVarID, "Units")<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)<br />

status = nf<strong>90</strong>_enddef(ncid)<br />

if (status /= nf<strong>90</strong>_noerr) call handle_err(status)


58 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide


Appendix A: Appendix A - Summary of <strong>Fortran</strong> <strong>90</strong> Interface 59<br />

Appendix A Appendix A - Summary of <strong>Fortran</strong><br />

<strong>90</strong> Interface<br />

Dataset Functions<br />

function nf<strong>90</strong>_<strong>in</strong>q_libvers()<br />

character(len = 80) :: nf<strong>90</strong>_<strong>in</strong>q_libvers<br />

function nf<strong>90</strong>_strerror(ncerr)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncerr<br />

character(len = 80) :: nf<strong>90</strong>_strerror<br />

function nf<strong>90</strong>_create(path, cmode, ncid)<br />

character (len = *), <strong>in</strong>tent(<strong>in</strong> ) :: path<br />

<strong>in</strong>teger, <strong>in</strong>tent(<strong>in</strong> ) :: cmode<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong> ) :: <strong>in</strong>itialsize<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong>out) :: chunksize<br />

<strong>in</strong>teger, <strong>in</strong>tent( out) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_create<br />

function nf<strong>90</strong>_open(path, mode, ncid, chunksize)<br />

character (len = *), <strong>in</strong>tent(<strong>in</strong> ) :: path<br />

<strong>in</strong>teger, <strong>in</strong>tent(<strong>in</strong> ) :: mode<br />

<strong>in</strong>teger, <strong>in</strong>tent( out) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(<strong>in</strong>out) :: chunksize<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_open<br />

function nf<strong>90</strong>_set_fill(ncid, fillmode, old_mode)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, fillmode<br />

<strong>in</strong>teger, <strong>in</strong>tent(out) :: old_mode<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_set_fill<br />

function nf<strong>90</strong>_redef(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_redef<br />

function nf<strong>90</strong>_enddef(ncid, h_m<strong>in</strong>free, v_align, v_m<strong>in</strong>free, r_align)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent( <strong>in</strong>) :: h_m<strong>in</strong>free, v_align, v_m<strong>in</strong>free, r_align<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_enddef<br />

function nf<strong>90</strong>_sync(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_sync<br />

function nf<strong>90</strong>_abort(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_abort<br />

function nf<strong>90</strong>_close(ncid)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_close<br />

function nf<strong>90</strong>_Inquire(ncid, nDimensions, nVariables, nAttributes, &<br />

unlimitedDimId)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

<strong>in</strong>teger, optional, <strong>in</strong>tent(out) :: nDimensions, nVariables, nAttributes, &<br />

unlimitedDimId<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire


60 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Dimension functions<br />

function nf<strong>90</strong>_def_dim(ncid, name, len, dimid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: len<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_def_dim<br />

function nf<strong>90</strong>_<strong>in</strong>q_dimid(ncid, name, dimid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_dimid<br />

function nf<strong>90</strong>_Inquire_Dimension(ncid, dimid, name, len)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, dimid<br />

character (len = *), optional, <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: len<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Dimension<br />

function nf<strong>90</strong>_rename_dim(ncid, dimid, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: dimid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_dim<br />

Variable functions<br />

function nf<strong>90</strong>_def_var(ncid, name, xtype, dimids, varid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: xtype<br />

<strong>in</strong>teger, dimension(:), <strong>in</strong>tent( <strong>in</strong>) :: dimids ! May be omitted, scalar,<br />

! vector<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_def_var<br />

function nf<strong>90</strong>_<strong>in</strong>q_varid(ncid, name, varid)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out) :: varid<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_varid<br />

function nf<strong>90</strong>_Inquire_Variable(ncid, varid, name, xtype, ndims, &<br />

dimids, nAtts)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), optional, <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: xtype, ndims<br />

<strong>in</strong>teger, dimension(*), optional, <strong>in</strong>tent(out) :: dimids<br />

<strong>in</strong>teger,<br />

optional, <strong>in</strong>tent(out) :: nAtts<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Variable<br />

function nf<strong>90</strong>_put_var(ncid, varid, values, start, stride, map)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

any valid type, scalar or array of any rank, &


Appendix A: Appendix A - Summary of <strong>Fortran</strong> <strong>90</strong> Interface 61<br />

<strong>in</strong>tent( <strong>in</strong>) :: values<br />

<strong>in</strong>teger, dimension(:), optional, <strong>in</strong>tent( <strong>in</strong>) :: start, count, stride, map<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_put_var<br />

function nf<strong>90</strong>_get_var(ncid, varid, values, start, stride, map)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

any valid type, scalar or array of any rank, &<br />

<strong>in</strong>tent(out) :: values<br />

<strong>in</strong>teger, dimension(:), optional, <strong>in</strong>tent( <strong>in</strong>) :: start, count, stride, map<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_get_var<br />

function nf<strong>90</strong>_rename_var(ncid, varid, newname)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: newname<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_var<br />

Attribute functions<br />

function nf<strong>90</strong>_Inquire_Attribute(ncid, varid, name, xtype, len, attnum)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>)<br />

:: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out), optional :: xtype, len, attnum<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Attribute<br />

function nf<strong>90</strong>_<strong>in</strong>q_attname(ncid, varid, attnum, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid, attnum<br />

character (len = *), <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_attname<br />

function nf<strong>90</strong>_put_att(ncid, varid, name, values)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character(len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

any valid type, scalar or array of rank 1, &<br />

<strong>in</strong>tent( <strong>in</strong>) :: values<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_put_att<br />

function nf<strong>90</strong>_get_att(ncid, varid, name, values)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character(len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

any valid type, scalar or array of rank 1, &<br />

<strong>in</strong>tent(out) :: values<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_get_att<br />

function nf<strong>90</strong>_copy_att(ncid_<strong>in</strong>, varid_<strong>in</strong>, name, ncid_out, varid_out)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid_<strong>in</strong>, varid_<strong>in</strong><br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid_out, varid_out<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_copy_att<br />

function nf<strong>90</strong>_rename_att(ncid, varid, curname, newname)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: curname, newname<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_rename_att<br />

function nf<strong>90</strong>_del_att(ncid, varid, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid


62 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>) :: name<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_del_att


Appendix B: Appendix B - FORTRAN 77 to <strong>Fortran</strong> <strong>90</strong> Transition Guide 63<br />

Appendix B Appendix B - FORTRAN 77 to<br />

<strong>Fortran</strong> <strong>90</strong> Transition Guide<br />

The new <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface<br />

The <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface to the netCDF library closely follows the FORTRAN 77 <strong>in</strong>terface.<br />

In most cases, function and constant names and argument lists are the same, except<br />

that nf<strong>90</strong> replaces nf <strong>in</strong> names. The <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface is much smaller than the FOR-<br />

TRAN 77 <strong>in</strong>terface, however. This has been accomplished by us<strong>in</strong>g optional arguments and<br />

overloaded functions wherever possible.<br />

Because FORTRAN 77 is a subset of <strong>Fortran</strong> <strong>90</strong>, there is no reason to modify work<strong>in</strong>g<br />

FORTRAN code to use the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface. New code, however, can easily be patterned<br />

after exist<strong>in</strong>g FORTRAN while tak<strong>in</strong>g advantage of the simpler <strong>in</strong>terface. Some compilers<br />

may provide additional support when us<strong>in</strong>g <strong>Fortran</strong> <strong>90</strong>. For example, compilers may issue<br />

warn<strong>in</strong>gs if arguments with <strong>in</strong>tent( <strong>in</strong>) are not set be<strong>for</strong>e they are passed to a procedure.<br />

The <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface is currently implemented as a set of wrappers around the base<br />

FORTRAN subrout<strong>in</strong>es <strong>in</strong> the netCDF distribution. Future versions may be implemented<br />

entirely <strong>in</strong> <strong>Fortran</strong> <strong>90</strong>, add<strong>in</strong>g additional error check<strong>in</strong>g possibilities.<br />

Changes to Inquiry functions<br />

In the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface there are two <strong>in</strong>quiry functions each <strong>for</strong> dimensions, variables,<br />

and attributes, and a s<strong>in</strong>gle <strong>in</strong>quiry function <strong>for</strong> datasets. These functions take optional arguments,<br />

allow<strong>in</strong>g users to request only the <strong>in</strong><strong>for</strong>mation they need. These functions replace<br />

the many-argument and s<strong>in</strong>gle-argument <strong>in</strong>quiry functions <strong>in</strong> the FORTRAN <strong>in</strong>terface.<br />

As an example, compare the attribute <strong>in</strong>quiry functions <strong>in</strong> the <strong>Fortran</strong> <strong>90</strong> <strong>in</strong>terface<br />

function nf<strong>90</strong>_Inquire_Attribute(ncid, varid, name, xtype, len, attnum)<br />

<strong>in</strong>teger, <strong>in</strong>tent( <strong>in</strong>) :: ncid, varid<br />

character (len = *), <strong>in</strong>tent( <strong>in</strong>)<br />

:: name<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent(out), optional :: xtype, len, attnum<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_Inquire_Attribute<br />

function nf<strong>90</strong>_<strong>in</strong>q_attname(ncid, varid, attnum, name)<br />

<strong>in</strong>teger,<br />

<strong>in</strong>tent( <strong>in</strong>) :: ncid, varid, attnum<br />

character (len = *), <strong>in</strong>tent(out) :: name<br />

<strong>in</strong>teger<br />

:: nf<strong>90</strong>_<strong>in</strong>q_attname<br />

with those <strong>in</strong> the FORTRAN <strong>in</strong>terface<br />

INTEGER FUNCTION NF_INQ_ATT (NCID, VARID, NAME, xtype, len)<br />

INTEGER FUNCTION NF_INQ_ATTID (NCID, VARID, NAME, attnum)<br />

INTEGER FUNCTION NF_INQ_ATTTYPE (NCID, VARID, NAME, xtype)<br />

INTEGER FUNCTION NF_INQ_ATTLEN (NCID, VARID, NAME, len)<br />

INTEGER FUNCTION NF_INQ_ATTNAME (NCID, VARID, ATTNUM, name)<br />

Changes to put and get function<br />

The biggest simplification <strong>in</strong> the <strong>Fortran</strong> <strong>90</strong> is <strong>in</strong> the nf<strong>90</strong> put var and nf<strong>90</strong> get var functions.<br />

Both functions are overloaded: the values argument can be a scalar or an array any<br />

rank (7 is the maximum rank allowed by <strong>Fortran</strong> <strong>90</strong>), and may be of any numeric type or<br />

the default character type. The netCDF library provides transparent conversion between<br />

the external representation of the data and the desired <strong>in</strong>ternal representation.


64 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

The start, count, stride, and map arguments to nf<strong>90</strong> put var and nf<strong>90</strong> get var are optional.<br />

By default, data is read from or written to consecutive values of start<strong>in</strong>g at the<br />

orig<strong>in</strong> of the netCDF variable; the shape of the argument determ<strong>in</strong>es how many values are<br />

read from or written to each dimension. Any or all of these arguments may be supplied to<br />

override the default behavior.<br />

Note also that <strong>Fortran</strong> <strong>90</strong> allows arbitrary array sections to be passed to any procedure,<br />

which may greatly simplify programm<strong>in</strong>g. For examples Section 4.6 [NF<strong>90</strong> PUT VAR],<br />

page 32 and Section 4.7 [NF<strong>90</strong> GET VAR], page 36.


Index 65


66 <strong>NetCDF</strong> <strong>Fortran</strong> <strong>90</strong> Interface Guide<br />

Index<br />

A<br />

attributes, add<strong>in</strong>g. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

C<br />

common netcdf commands. . . . . . . . . . . . . . . . . . . . . 1<br />

compil<strong>in</strong>g with netCDF library . . . . . . . . . . . . . . . . 6<br />

D<br />

dataset, creat<strong>in</strong>g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

datasets, overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

dimensions, add<strong>in</strong>g. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

E<br />

error handl<strong>in</strong>g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

I<br />

<strong>in</strong>terface descriptions . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

L<br />

l<strong>in</strong>k<strong>in</strong>g to netCDF library . . . . . . . . . . . . . . . . . . . . . 6<br />

N<br />

NF<strong>90</strong> ABORT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

NF<strong>90</strong> ABORT , example . . . . . . . . . . . . . . . . . . . . . 18<br />

NF<strong>90</strong> CLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

NF<strong>90</strong> CLOSE , example . . . . . . . . . . . . . . . . . . . . . 14<br />

NF<strong>90</strong> CLOSE, typical use . . . . . . . . . . . . . . . . . . . . . 1<br />

NF<strong>90</strong> COPY ATT. . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

NF<strong>90</strong> COPY ATT, example . . . . . . . . . . . . . . . . . . 53<br />

NF<strong>90</strong> CREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

NF<strong>90</strong> CREATE , example . . . . . . . . . . . . . . . . . . . . . 9<br />

NF<strong>90</strong> CREATE, typical use . . . . . . . . . . . . . . . . . . . 1<br />

NF<strong>90</strong> DEF DIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

NF<strong>90</strong> DEF DIM, example. . . . . . . . . . . . . . . . . . . . 21<br />

NF<strong>90</strong> DEF DIM, typical use . . . . . . . . . . . . . . . . . . 1<br />

NF<strong>90</strong> DEF VAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

NF<strong>90</strong> DEF VAR, example . . . . . . . . . . . . . . . . . . . 28<br />

NF<strong>90</strong> DEF VAR, typical use . . . . . . . . . . . . . . . . . . 1<br />

NF<strong>90</strong> DEL ATT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

NF<strong>90</strong> DEL ATT , example . . . . . . . . . . . . . . . . . . . 56<br />

NF<strong>90</strong> ENDDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

NF<strong>90</strong> ENDDEF , example. . . . . . . . . . . . . . . . . . . . 13<br />

NF<strong>90</strong> ENDDEF, typical use . . . . . . . . . . . . . . . . . . . 1<br />

NF<strong>90</strong> GET ATT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

NF<strong>90</strong> GET ATT, example . . . . . . . . . . . . . . . . . . . 51<br />

NF<strong>90</strong> GET ATT, typical use . . . . . . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> GET VAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

NF<strong>90</strong> GET VAR, example . . . . . . . . . . . . . . . . . . . 37<br />

NF<strong>90</strong> GET VAR, typical use . . . . . . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> INQ ATTNAME, typical use . . . . . . . . . . . . 2<br />

NF<strong>90</strong> INQ DIMID. . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

NF<strong>90</strong> INQ DIMID , example . . . . . . . . . . . . . . . . . 22<br />

NF<strong>90</strong> INQ DIMID, typical use . . . . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> INQ LIBVERS . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

NF<strong>90</strong> INQ LIBVERS, example . . . . . . . . . . . . . . . . 8<br />

NF<strong>90</strong> INQ VARID . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />

NF<strong>90</strong> INQ VARID , example . . . . . . . . . . . . . . . . . 29<br />

NF<strong>90</strong> INQ VARID, typical use . . . . . . . . . . . . . . 2, 3<br />

NF<strong>90</strong> Inquire, typical use . . . . . . . . . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> Inquire Att and NF<strong>90</strong> INQ ATTNAME<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

NF<strong>90</strong> Inquire Att and NF<strong>90</strong> INQ ATTNAME,<br />

example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

NF<strong>90</strong> Inquire Attribute, typical use . . . . . . . . . . . . 2<br />

NF<strong>90</strong> Inquire Dimension . . . . . . . . . . . . . . . . . . . . . 23<br />

NF<strong>90</strong> Inquire Dimension , example . . . . . . . . . . . 23<br />

NF<strong>90</strong> Inquire Dimension, typical use . . . . . . . . . . . 2<br />

NF<strong>90</strong> Inquire Variable . . . . . . . . . . . . . . . . . . . . . . . 30<br />

NF<strong>90</strong> Inquire Variable , example . . . . . . . . . . . . . 30<br />

NF<strong>90</strong> Inquire Variable, typical use . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> OPEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

NF<strong>90</strong> OPEN , example . . . . . . . . . . . . . . . . . . . . . . 10<br />

NF<strong>90</strong> OPEN, typical use . . . . . . . . . . . . . . . . . . . . . . 2<br />

NF<strong>90</strong> PUT ATT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

NF<strong>90</strong> PUT ATT, example . . . . . . . . . . . . . . . . . . . 48<br />

NF<strong>90</strong> PUT ATT, typical use . . . . . . . . . . . . . . . . 1, 3<br />

NF<strong>90</strong> PUT VAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

NF<strong>90</strong> PUT VAR, example . . . . . . . . . . . . . . . . . . . 32<br />

NF<strong>90</strong> PUT VAR, typical use . . . . . . . . . . . . . . . . 1, 3<br />

NF<strong>90</strong> REDEF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

NF<strong>90</strong> REDEF , example . . . . . . . . . . . . . . . . . . . . . 12<br />

NF<strong>90</strong> REDEF, typical use. . . . . . . . . . . . . . . . . . . . . 4<br />

NF<strong>90</strong> RENAME ATT . . . . . . . . . . . . . . . . . . . . . . . 55<br />

NF<strong>90</strong> RENAME ATT, example . . . . . . . . . . . . . . 55<br />

NF<strong>90</strong> RENAME DIM . . . . . . . . . . . . . . . . . . . . . . . 24<br />

NF<strong>90</strong> RENAME DIM , example . . . . . . . . . . . . . . 24<br />

NF<strong>90</strong> RENAME VAR . . . . . . . . . . . . . . . . . . . . . . . 43<br />

NF<strong>90</strong> RENAME VAR , example. . . . . . . . . . . . . . 43<br />

NF<strong>90</strong> SET FILL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

NF<strong>90</strong> SET FILL , example . . . . . . . . . . . . . . . . . . . 19<br />

NF<strong>90</strong> STRERROR . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

NF<strong>90</strong> STRERROR, example . . . . . . . . . . . . . . . . . . 8<br />

NF<strong>90</strong> STRERROR, <strong>in</strong>troduction. . . . . . . . . . . . . . . 5<br />

NF<strong>90</strong> SYNC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

NF<strong>90</strong> SYNC , example . . . . . . . . . . . . . . . . . . . . . . . 16<br />

R<br />

read<strong>in</strong>g dataset with unknown names . . . . . . . . . . . 2<br />

U<br />

users’ guide, netcdf . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

V<br />

variables, add<strong>in</strong>g. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

W<br />

writ<strong>in</strong>g to exist<strong>in</strong>g dataset . . . . . . . . . . . . . . . . . . . . . 3

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!