source: trunk/src/nc2struct.m @ 1109

Last change on this file since 1109 was 1107, checked in by g7moreau, 3 years ago

Update Copyright to 2022

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