Saving NetCdf in Matlab

About this example

In atmospheric sciences, we often deal with 4 dimensional fields. NetCdf is a practical format to save such data. Here I give an example where I save temperature in function of time, pressure, latitude, longitude

Code

%Open the file
ncid = netcdf.create(['./thefile.nc'],'NC_WRITE')
 
%Define the dimensions
dimidt = netcdf.defDim(ncid,'time',mytimesize);
dimidp = netcdf.defDim(ncid,'pressure',mypressuresize);
dimidlat = netcdf.defDim(ncid,'latitude',mylatitudesize);
dimidlon = netcdf.defDim(ncid,'longitude',mylongitudesize);
 
%Define IDs for the dimension variables (pressure,time,latitude,...)
time_ID=netcdf.defVar(ncid,'time','double',[dimidt]);
pressure_ID=netcdf.defVar(ncid,'pressure','double',[dimidp]);
latitude_ID=netcdf.defVar(ncid,'latitude','double',[dimidlat]);
longitude_ID=netcdf.defVar(ncid,'longitude','double',[dimidlon]);
 
%Define the main variable ()
temperature_ID = netcdf.defVar(ncid,'temperature','double',[dimidt dimidp dimidlat dimidlon]);
 
%We are done defining the NetCdf
netcdf.endDef(ncid);
 
%Then store the dimension variables in
netcdf.putVar(ncid,time_ID,mytimearray);
netcdf.putVar(ncid,pressure_ID,mypressurearray);
netcdf.putVar(ncid,latitude_ID,mylatitudearray);
netcdf.putVar(ncid,longitude_ID,mylongitudearray);
 
%Then store my main variable
netcdf.putVar(ncid,temperature_ID,mytemperaturearray);
 
%We're done, close the netcdf
netcdf.close(ncid)

24 thoughts on “Saving NetCdf in Matlab

  1. Matt

    Dear Patrick

    This is really helpful code. Thanks a whole lot for sharing it.
    I have been trying to tweak it for another close-related use I have, but try as I might, I haven’t been able to…

    I want to export as a netCDF file a matrix of a single daily NCAR (surface flux) 2m temperature reanalysis. The critical thing is, it needs to be for the default global extent of the reanlaysis (i.e. 192 rows, 94 cols) and to retain the specific lat and long of the T62 Gaussian grid i.e. 88.542N to 88.542S for the lat and 0 to 358.125E. This makes it a simple 2D export, with time no longer a variable, but, the important thing is retaining the ‘original’ lat and long.

    Since my ‘mytemperature’ array is 94×192 I think I only need to successfully manipulate the netcdf dimensions you specify as ‘mylatutudesize’ and ‘mylongitudesize’.
    Can you suggest to me what those values should be?
    One thing I am snagged on is that these dimensions are required to be scalars, but the ‘real’ lat and lon dimensions are not e.g. 88.542

    I was even also trying to use ncwriteschema to adopt the dimensions scheme of the original input .nc file from NCAR, but no joy.

    Would it be time consuming for you to show us how please?

    Many thanks for sharig your thoughts on your site!
    Matt

    Reply
    1. Patrick Martineau Post author

      Hi Matt,
      The ‘mylongitudesize’ (integer, one element) is only the number of longitude of your grid, not the actual values. In netcdf format, you have to define the dimension size first…

      The longitude values are actually stored at that line: netcdf.putVar(ncid,longitude_ID,mylongitudearray) and the values can be single precision our double precision. “mylongitudearray” is your longitude vector. In netcdf format, pressure, latitude or longitude values are actually variables stored similar to temperature for example, and can be stored using same command.

      Hope this helps!

      Reply
  2. izidor

    This helped me a lot, but there is one more issue I still have. If I create in matlab n-by-m matrix (say for temperature), data=randn(n,m), and I want to save that as netCDF for n latitudes, m longitudes, 1 level (e.g. 0) and 1 time (e.g. 1234), what is then the final step? Do I do start = [0 0 0 0] , count = [n m 1 1] ? But what is then “mytemperaturearray”, clearly it is not a n-by-m matrix. Could you help?

    Reply
    1. Patrick Martineau Post author

      Hi Izidor,
      From my understanding, your problem is that you want to save data that is function of latitude and longitude only and that your pressure and time dimension are of singleton dimension.

      In my example, dimensions are {time x pressure x latitude x longitude}. Therefore your matrix “mytemperaturearray” should be of size 1 x 1 x n x m. To make a matrix of size n x m into size 1 x 1 x n x m you can do [newarray]=permute(oldarray,[3 4 1 2]). This usually works well for me.

      Is your goal to save data in a loop level-by-level or day-by-day? You would have to use more advanced options of netcdf.putVar in that case. In this simple example, data is saved in one single step.

      Reply
  3. Alex

    Thanks a lot for the code example, it’s really helpful.

    On line 8, you have:
    dimidlon = netcdf.defDim(ncid,’latitude’,mylongitudesize);

    I think it should be
    dimidlon = netcdf.defDim(ncid,’longitude’,mylongitudesize);

    Reply
  4. RK

    Dear Patrick,

    I can do writing for unlimited array.

    =========
    dimidt = netcdf.defDim(ncid,’time’,netcdf.getConstant(‘NC_UNLIMITED’));
    .
    .
    .
    time_ID=netcdf.defVar(ncid,’time’,’short’,[dimidt]);
    netcdf.putVar(ncid,time_ID,0,mytimearray,int16([0:mytimearray]));
    =======

    Thanks any ways for your posting 🙂

    Cheers,
    -r/K-

    Reply
  5. Carlos

    Hi PAtrick!

    Patrick, I’m user new in Matlab and I’m needing save my data in netcdf format.

    I did test using your script with my data, but not give right because I not know as create the variables necessary to last part from your script.

    %Then store the dimension variables in
    netcdf.putVar(ncid,time_ID,mytimearray);
    netcdf.putVar(ncid,pressure_ID,mypressurearray);
    netcdf.putVar(ncid,latitude_ID,mylatitudearray);
    netcdf.putVar(ncid,longitude_ID,mylongitudearray);

    How could I create the variables mytimearray, mylatitudearray and mylongitudearray?
    I have variables to time, longitude and latitude, but that not are array…

    Would you have an script more complete (with all steps from data entry to the rescue of the variables in netcdf) for I understand better!!

    Thanks

    Cheers!@
    Carlos

    Reply
    1. Patrick Martineau Post author

      Hi Carlos,
      The dimension variables like pressure time latitude and longitude can be 1-D arrays (vectors)
      The mytemperaturearray however needs to be a multidimensional array. In this case it needs
      to be a 4-D array. Unfortunately I do not have a fully working example to share at this time. You
      might want to refer to the Matlab documentation if you have any issue, there may be useful
      examples on their website.

      Reply
  6. Carlos

    Hi Dear Martineau

    Martineau, I recently made a script to save the data in netcdf grads and it worked. I did the first tests to see if my variable was within the netcdf using ncview and everything went well.

    However when trying to open this data in Grads, an error occurred. The file opens with all dimensions but not the data.
    Do you know if there is any statement that the netcdf generated in matlab can be opened in grads?

    Cheers!

    Carlos

    Reply
  7. Magdalena

    Hello Patrick,

    Thank you for the scritp, it was very helpful!

    I’m having problems saving a netcdf file with a nonlinear grid (it has a meshed lat- lon) and I need to save those variables as a matrix. So the size of lat and lon is 130×143 and the size of my variable is 130x143x14000

    do you know how can I adapt your script as to save the variables that way?

    Thank you, Magdalena

    Reply
    1. Patrick Martineau Post author

      Hi Magdalena,
      Please let me know if I this makes any sense! From my knowledge, netCdf is working fine for rectangular grids. Because you have a non-regular grid you have a latitude matrix of 130×143 and a longitude matrix of 130×143 which can’t be stored with the method I’m using here. I would simply create two dummy dimensions x (length of 130) and y (length of 143) and then store latitude, and longitude as variables depending on x and y [lon(x,y) lat(x,y)]. Then your data can be saved as [variable(x,y,time)]. Here x and y would not have any physical meaning but would only describe the dimension of your matrix…

      Reply
  8. Mariano

    Hello Patrick,

    Thank you for this script! I’m having trouble when opening the netcdf I’ve saved with this script with ncview or GrADS. Could you help me with this? I’ll try to explain why:

    So I have my variable, OLR, 4 dimensions (time x pressure x lat x lon), pressure a singleton dimension that I added so as to match this script. I pretty much follow everything, and I get the netcdf file at the end. However, when I use ncdump -h on the .nc, I get:

    double time(time) ;
    double pressure(pressure);
    double latitude(latitude) ;
    double longitude(longitude) ;
    double aolr(longitude, latitude, pressure, time) ;

    I think I might be having a problem in the order of the dimensions in my matlab array (as said above, (time x pressure x lat x lon)) and in the netcdf file (double aolr(longitude, latitude, pressure, time) ) and this might be causing the error, as when I open the .nc file with ncview, it shows that I have as many times as longitudes I really have (Say, if originally the dimensions are in matlab 10800 x 1 x 66 x 384, ncview understands that I have 384 times, when those were longitudes).

    GrADS is also unable to open the .nc file because some dimension problem.

    Hope I’m being clear and that you can help me,
    Thank you!
    Mariano

    Reply
  9. Magdalena

    Hello Patrick, I forgot to answer you. Yes it worked, thank you! I leave an example for a variable “PAV” for anyone who has the same problem.

    x=ones(size(lon,1),1);
    y=ones(size(lon,2),1);

    f_out=[ path_out ‘file.nc’ ];
    ncid = netcdf.create(f_out,’NC_WRITE’);
    % Crear dimensiones
    dimid_lon = netcdf.defDim(ncid,’longitude’,size(x,1));
    dimid_lat = netcdf.defDim(ncid,’latitude’,size(y,1));
    dimid_time = netcdf.defDim(ncid,’time’,size(time,1));
    % Crear variables y atributos
    varid_lon = netcdf.defVar(ncid,’longitude’,’double’,[dimid_lon,dimid_lat]);
    netcdf.putAtt(ncid,varid_lon,’long_name’,’Longitude’)
    netcdf.putAtt(ncid,varid_lon,’units’,’degrees_east’)
    %
    varid_lat = netcdf.defVar(ncid,’latitude’,’double’,[dimid_lon,dimid_lat]);
    netcdf.putAtt(ncid,varid_lat,’long_name’,’Latitude’)
    netcdf.putAtt(ncid,varid_lat,’units’,’degrees_north’)
    %
    varid_time = netcdf.defVar(ncid,’time’,’double’,dimid_time);
    netcdf.putAtt(ncid,varid_time,’long_name’,’Time’)
    netcdf.putAtt(ncid,varid_time,’units’,’6H since 2008-01-01′)
    %
    varid_PAV = netcdf.defVar(ncid,’PAV_95′,’double’,[dimid_lon,dimid_lat,dimid_time]);
    netcdf.putAtt(ncid,varid_PAV,’long_name’,’Variable’)
    netcdf.putAtt(ncid,varid_PAV,’units’,’mm/day’)
    netcdf.endDef(ncid)
    %%% Agregar datos de coordenadas %%%%%%%%%%%%%%%%%%%%%%%%%%%
    netcdf.putVar(ncid,varid_lon,[0 0],[size(x,1) size(y,1)],lon(:,:));
    netcdf.putVar(ncid,varid_lat,[0 0],[size(x,1) size(y,1)],lat(:,:));
    netcdf.putVar(ncid,varid_time,time);

    %%%%%% agregando variable principal%%%%%%%%%%%%%%%%%%%%%%%%
    for tt=1:size(time,1)
    netcdf.putvar(ncid,varid_PAV,[0 0 tt-1],[size(x,1) size(y,1) 1],PAV(:,:,tt))
    end
    netcdf.close(ncid)
    end

    Reply
  10. faiz fajary

    Hello
    my name is faiz

    I have made myfile.nc using above script, but when I opened it in Grads, the values is odd
    have any idea which part I did mistake?

    regards,
    -faiz-

    Reply
  11. Md Shamim Shams

    Hi Patrick,

    First of all many thanks to post such an useful code. My problem is almost similar. I am working with NOAA file named hgt.mon.mean.nc where it is arranged as [lon,lat,level,time] or 144x73x17x804 way in monthly mean.

    I like to capture data HGT data from mentioned file as monthly mean from specified longitude and latitude like
    east = 290;
    west = 30;
    north = 50;
    south = -60

    for specific period of time 1971 to 2011.

    And finally saved data in ascii or excel format. Do you have any specific code for this in Matlab? If you then it will be really helpfull.

    Best regards.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *