source: trunk/src/nc2struct.m @ 1201

Last change on this file since 1201 was 1201, checked in by sommeria, 5 hours ago

various improvements...

File size: 13.7 KB
RevLine 
[1201]1%'nc2struct': reads a NetCDF file as a corresponding Matlab structure.
[1095]2% or directly read the a matlab data file .mat (calling the fct mat2struct.m)
[8]3% it reads all the global attributes and all variables, or a selected list.
4% The corresponding dimensions and variable attributes are then extracted
5%----------------------------------------------------------------------
[755]6% function [Data,var_detect,ichoice,errormsg]=nc2struct(nc,varargin)
[8]7%
8% OUTPUT:
[816]9%  Data: structure containing all the information of the NetCDF file (or NetCDF object)
[140]10%           with (optional)fields:
11%                    .ListGlobalAttribute: cell listing the names of the global attributes
[55]12%                    .Att_1,Att_2... : values of the global attributes
[816]13%                    .ListVarName: list of variable names to select (cell array of  char strings {'VarName1', 'VarName2',...} )
14%                    .VarDimName: list of dimension names for each element of .ListVarName (cell array of string cells)
[55]15%                    .Var1, .Var2....: variables (Matlab arrays) with names listed in .ListVarName
[693]16%                  .ListDimName=list of dimension (added information, not requested for field description)
17%                  .DimValue= vlalues of dimensions (added information, not requested for field description)
[816]18%                  .VarType= integers giving the type of variable as coded by netcdf =2 for char, =4 for single,=( for double
[140]19%  var_detect: vector with same length as the cell array ListVarName, = 1 for each detected variable and 0 else.
[816]20%            var_detect=[] in the absence of input cell array
21%  ichoice: index of the selected line in the case of multiple choice
22%        (cell array of varible names with multiple lines) , =[] by default
23%
24% INPUT:
25%  nc:  name of a NetCDF file (char string) or NetCDF object
[140]26%  additional arguments:
[816]27%       -no additional arguments: all the variables of the NetCDF file are read.
[1181]28%       - empty argument []: the output field structure is limited to the names of variables, without their values
[816]29%       -a cell array, ListVarName, made of  char strings {'VarName1', 'VarName2',...} )
[648]30%         if ListVarName=[] or {}, no variable value is read (only global attributes and list of variables and dimensions)
[816]31%         if ListVarName is absent, or = '*', ALL the variables of the NetCDF file are read.
[747]32%         if ListVarName is a cell array with n lines, the set of variables will be sought by order of priority in the list,
33%            while output names will be set by the first line
34%       - the string 'ListGlobalAttribute' followed by a list of attribute  names: reads only these attributes (fast reading)
[816]35%       - the string 'TimeVarName', a string (the name of the variable considered as time), an integer or vector with integer values
[771]36%            representing time indices to select for each variable, the cell of other input variable names.
[648]37
[1181]38
[809]39%=======================================================================
[1126]40% Copyright 2008-2024, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
[809]41%   http://www.legi.grenoble-inp.fr
[1127]42%   Joel.Sommeria - Joel.Sommeria (A) univ-grenoble-alpes.fr
[809]43%
[8]44%     This file is part of the toolbox UVMAT.
[809]45%
[8]46%     UVMAT is free software; you can redistribute it and/or modify
[809]47%     it under the terms of the GNU General Public License as published
48%     by the Free Software Foundation; either version 2 of the license,
49%     or (at your option) any later version.
50%
[8]51%     UVMAT is distributed in the hope that it will be useful,
52%     but WITHOUT ANY WARRANTY; without even the implied warranty of
53%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
[809]54%     GNU General Public License (see LICENSE.txt) for more details.
55%=======================================================================
[816]56
[747]57function [Data,var_detect,ichoice,errormsg]=nc2struct(nc,varargin)
58errormsg='';%default error message
[55]59if isempty(varargin)
[56]60    varargin{1}='*';
[8]61end
62
[1095]63%% default output
64Data=[];%default
65var_detect=[];%default
66ichoice=[];%default
[816]67
[1095]68%% open the NetCDF (or .mat) file for reading
69if ischar(nc)
70    testfile=1;
71    if exist(nc,'file')
72        if ~isempty(regexp(nc,'.mat$'))
73            Data=mat2struct(nc,varargin{1});
74            return
75        else
[150]76            try
[747]77                nc=netcdf.open(nc,'NC_NOWRITE');
[227]78            catch ME
[747]79                errormsg=['ERROR opening ' nc ': ' ME.message];
80                return
[150]81            end
[1095]82        end
83    else %case of OpenDAP files
84        if regexp(nc,'^http://')
85            try
86                nc=netcdf.open(nc,'NC_NOWRITE');
87            catch ME
88                errormsg=['ERROR opening ' nc ': ' ME.message];
89                return
90            end
[8]91        else
[747]92            errormsg=['ERROR:file ' nc ' does not exist'];
93            return
[8]94        end
95    end
[1095]96else
97    testfile=0;
98end
[816]99
[1095]100%% short reading option for global attributes only, if the first argument is 'ListGlobalAttribute'
101if isequal(varargin{1},'ListGlobalAttribute')
102    for ilist=2:numel(varargin)
103        valuestr=[];%default
104        try
105            valuestr = netcdf.getAtt(nc,netcdf.getConstant('NC_GLOBAL'),varargin{ilist});
106        catch ME
[8]107        end
[1162]108        Data.(varargin{ilist})=valuestr;
[8]109    end
[1095]110    netcdf.close(nc)
111    return
112end
[816]113
[1095]114%% time variable or dimension
115input_index=1;
116CheckTimeVar=0;
117TimeVarName='';
118if isequal(varargin{1},'TimeVarName')
119    TimeVarName=varargin{2};
120    CheckTimeVar=1;
121    TimeIndex=varargin{3};
122    input_index=4;% list of variables to read is at fourth argument
123elseif isequal(varargin{1},'TimeDimName')
124    TimeDimName=varargin{2};
125    TimeIndex=varargin{3};
126    input_index=4;
127end
[816]128
[1095]129%% full reading: get the nbre of dimensions, variables, global attributes
130ListVarName=varargin{input_index};
131[ndims,nvars,ngatts]=netcdf.inq(nc);%nbre of dimensions, variables, global attributes, in the NetCDF file
[816]132
[1095]133%%  -------- read all global attributes (constants)-----------
134Data.ListGlobalAttribute={};%default
135att_key=cell(1,ngatts);%default
136for iatt=1:ngatts
137    keystr= netcdf.inqAttName(nc,netcdf.getConstant('NC_GLOBAL'),iatt-1);
138    valuestr = netcdf.getAtt(nc,netcdf.getConstant('NC_GLOBAL'),keystr);
139    keystr=regexprep(keystr,{'\','/','\.','-',' '},{'','','','',''});%remove  '\','.' or '-' if exists
140    if strcmp(keystr(1),'_')
141        keystr(1)=[];
142    end
143    try
144        if ischar(valuestr) %& length(valuestr)<200 & double(valuestr)<=122 & double(valuestr)>=48 %usual characters
145            eval(['Data.' keystr '=''' valuestr ''';'])
146        elseif isnumeric(valuestr)
147            eval(['Data.' keystr '=valuestr;'])
148        else
149            eval(['Data.' keystr '='';'])
[227]150        end
[1095]151        att_key{iatt}=keystr;
152    catch ME
153        att_key{iatt}=['attr_' num2str(iatt)];
154        Data.(att_key{iatt})=[];
[8]155    end
[1095]156end
157Data.ListGlobalAttribute=att_key;
[816]158
[1095]159%%  -------- read dimension names-----------
160ListDimNameNetcdf=cell(1,ndims);
161dim_value=zeros(1,ndims);
162for idim=1:ndims %loop on the dimensions of the NetCDF file
163    [ListDimNameNetcdf{idim},dim_value(idim)] = netcdf.inqDim(nc,idim-1);%get name and value of each dimension
164end
165if ~isempty(ListDimNameNetcdf)
166    flag_used=zeros(1,ndims);%initialize the flag indicating the selected dimensions in the list (0=unused)
167end
168if isequal(varargin{1},'TimeDimName')% time dimension introduced
169    TimeDimIndex=find(strcmp(TimeDimName,ListDimNameNetcdf));
170    if isempty(TimeDimIndex)
171        errormsg=['requested time dimension ' varargin{2} ' not found'];
172        return
[8]173    end
[1095]174    if dim_value(TimeDimIndex)<varargin{3}
175        errormsg=['requested time index ' num2str(varargin{3}) ' exceeds matrix dimension'];
176        return
[8]177    end
[1095]178end
[816]179
[1095]180%%  -------- read names of variables -----------
181ListVarNameNetcdf=cell(1,nvars); %default
182dimids=cell(1,nvars);
183nbatt=zeros(1,nvars);
184for ncvar=1:nvars %loop on the variables of the NetCDF file
185    %get name, type, dimensions and attribute numbers of each variable
186    [ListVarNameNetcdf{ncvar},xtype(ncvar),dimids{ncvar},nbatt(ncvar)] = netcdf.inqVar(nc,ncvar-1);
187end
[747]188%     testmulti=0;
[1095]189if isequal(ListVarName,'*')||isempty(ListVarName)
190    var_index=1:nvars; %all the variables are selected in the NetCDF file
191    Data.ListVarName=ListVarNameNetcdf;
192else   %select input variables, if requested by the input ListVarName
193    check_keep=ones(1,size(ListVarName,2));
194    for ivar=1:size(ListVarName,2) % check redondancy of variable names
195        if ~isempty(find(strcmp(ListVarName{1,ivar},ListVarName(1:ivar-1)), 1))
196            check_keep(ivar)=0;% the variable #ivar is already in the list
[517]197        end
[1095]198    end
199    ListVarName=ListVarName(:,logical(check_keep));
[1195]200    iline=size(ListVarName,1);   
[1095]201    %ListVarName=ListVarName(iline,:);% select the appropriate option for input variable (lin ein the input name matrix)
202    if CheckTimeVar
203        TimeVarIndex=find(strcmp(TimeVarName,ListVarNameNetcdf),1); %look for the index of the time variable in the netcdf list
204        if isempty(TimeVarIndex)
205            errormsg='requested variable for time is missing';
206            return
[747]207        end
[1095]208        TimeDimIndex=dimids{TimeVarIndex}(1)+1;
209        ListVarName=[ListVarName {TimeVarName}];
210    end
211    var_index=zeros(1,size(ListVarName,2));%default list of variable indices
212    for ivar=1:size(ListVarName,2)
213        search_index=find(strcmp(ListVarName{iline,ivar},ListVarNameNetcdf),1);%look for the variable name in the list of NetCDF file
214        if ~isempty(search_index)
215            var_index(ivar)=search_index;%index of the netcdf list corresponding to the input list index ivar
[8]216        end
217    end
[1095]218    var_detect=(var_index~=0);%=1 for detected variables
219    list_index=find(var_index);% indices in the input list corresponding to a detected variable
220    var_index=var_index(list_index);% NetCDF variable indices corresponding to the output list of read variable
221    Data.ListVarName=ListVarName(1,list_index);%the first line of ListVarName sets the output names of the variables
222end
[816]223
[1095]224%% get the dimensions and attributes associated to  variables
225var_dim=cell(size(var_index));% initiate list of dimensions for variables
226for ivar=1:length(var_index)
227    var_dim{ivar}=dimids{var_index(ivar)}+1; %netcdf dimension indices used by the variable #ivar
228    Data.VarDimName{ivar}=ListDimNameNetcdf(var_dim{ivar});
229    flag_used(var_dim{ivar})=ones(size(var_dim{ivar}));%flag_used =1 for the indices of used dimensions
230    for iatt=1:nbatt(var_index(ivar))
231        attname = netcdf.inqAttName(nc,var_index(ivar)-1,iatt-1);
232        valuestr= netcdf.getAtt(nc,var_index(ivar)-1,attname);
233        attname=regexprep(attname,{'\','/','\.','-',' '},{'','','','',''});%remove  '\','.' or '-' if exists
234        if strcmp(attname(1),'_')
235            attname(1)=[];
236        end
237        try
238            if ~isempty(valuestr)
239                Data.VarAttribute{ivar}.(attname)=valuestr;
[227]240            end
[1095]241        catch ME
242            display(attname)
243            display(valuestr)
244            display(ME.message)
245            Data.VarAttribute{ivar}.(['atrr_' num2str(iatt)])='not read';
[8]246        end
247    end
[1095]248end
[816]249
[1095]250%% select the dimensions used for the set of input variables
251if ~isempty(var_index)
252    dim_index=find(flag_used);%list of netcdf dimensions indices corresponding to used dimensions
253    Data.ListDimName=ListDimNameNetcdf(dim_index);
254    Data.DimValue=dim_value(dim_index);
255    if input_index==4% if a dimension is selected as time
256        Data.DimValue(TimeDimIndex)=numel(TimeIndex);
[8]257    end
[1095]258end
[816]259
[1095]260%% get the values of the input variables
261if  ~isempty(ListVarName)
262    for ivar=1:length(var_index)
263        VarName=Data.ListVarName{ivar};
264        VarName=regexprep(VarName,'-','_'); %suppress '-' if it exists in the NetCDF variable name (leads to errors in matlab)
265        if input_index==4% if a dimension is selected as time
266            ind_vec=zeros(1,numel(var_dim{ivar}));% vector with zeros corresponding to al the dimensions of the variable VarName
267            ind_size=dim_value(var_dim{ivar});% vector giving the size (for each dimension) of the variable VarName
268            index_time=find(var_dim{ivar}==TimeDimIndex);
269            if ~isempty(index_time)
270                if ind_size(index_time)<max(TimeIndex)
271                    errormsg=['requested index ' num2str(TimeIndex) ' exceeds matrix dimension'];
272                    return
[816]273                end
[1194]274                ind_vec(index_time)=TimeIndex(1)-1;% selected index(or indices) to read
[1095]275                ind_size(index_time)=numel(TimeIndex);%length of the selected set of time indices
276                if numel(TimeIndex)==1 && ~strcmp(VarName,TimeVarName)
277                    Data.VarDimName{ivar}(index_time)=[];% for a single selected time remove the time in the list of dimensions (except for tTime itself)
278                end
[648]279            end
[1095]280            Data.(VarName)=netcdf.getVar(nc,var_index(ivar)-1,ind_vec,ind_size); %read the variable data
281            Data.(VarName)=squeeze(Data.(VarName));%remove singeton dimension
282        else
[1196]283%                        disp(VarName)
284%            xtype(var_index(ivar))
[1095]285            Data.(VarName)=netcdf.getVar(nc,var_index(ivar)-1); %read the whole variable data
[1196]286        end   
287        if xtype(var_index(ivar))==5 %single precision
288             Data.(VarName)=double(Data.(VarName)); %transform all variables to double  pecision
289        end
290    %    Data.(VarName)=double(Data.(VarName)); %transform all variables to double  pecision
[1195]291        if isfield(Data,'VarAttribute') && numel(Data.VarAttribute)>=ivar && isfield(Data.VarAttribute{ivar},'scale_factor')
[1196]292            Data.(VarName)=Data.VarAttribute{ivar}.scale_factor *double(Data.(VarName));
[8]293        end
294    end
[1095]295end
296Data.VarType=xtype(var_index);
[816]297
[1095]298%%  -------- close fle-----------
299if testfile==1
300    netcdf.close(nc)
301end
[816]302
Note: See TracBrowser for help on using the repository browser.