source: trunk/src/nc2struct.m @ 899

Last change on this file since 899 was 871, checked in by sommeria, 10 years ago

histo improved

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