source: trunk/src/nc2struct.m @ 768

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