source: trunk/src/nc2struct.m @ 1063

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