Changeset 27874


Ignore:
Timestamp:
08/08/23 11:26:37 (20 months ago)
Author:
musselman
Message:

Fixed bugs so that read/write files function interchangeably on inversion notebooks

Location:
issm/trunk/src/m/contrib/musselman
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified issm/trunk/src/m/contrib/musselman/read_netCDF.m

    r27864 r27874  
    1717
    1818function model_copy = read_netCDF(filename)
    19     fprintf('NetCDF42C v1.1.12\n');
     19    fprintf('NetCDF42C v1.1.13\n');
    2020
    2121    % make a model framework to fill that is in the scope of this file
     
    3939        catch
    4040        end % 'results' group doesn't exist
    41 
    4241
    4342        % see if inversion is in there, if it is we may have to instantiate some classes
     
    8483    global NCData;
    8584    inversionGroup = netcdf.inqNcid(NCData, "inversion");
    86     varid = netcdf.inqVarID(inversionGroup,'inversion_class_name')
     85    varid = netcdf.inqVarID(inversionGroup, 'inversion_class_name');
    8786    inversion_class = convertCharsToStrings(netcdf.getVar(inversionGroup, varid,'char'));
    88     if inversion_class == 'm1qn3inversion'
     87    if strcmp(inversion_class, 'm1qn3inversion')
    8988        model_copy.inversion = m1qn3inversion();
    9089        disp('Successfully created inversion class instance: m1qn3inversion')
    91     elseif inversion_class == 'taoinversion'
     90    elseif strcmp(inversion_class, 'taoinversion')
    9291        model_copy.inversion = taoinversion();
    9392        disp('Successfully created inversion class instance: taoinversion')
    9493    else
     94        disp('No inversion class was found')
    9595    end
    9696end
     
    109109        for variable = variables
    110110            [varname, xtype, dimids, numatts] = netcdf.inqVar(group_location_in_file, variable);
    111             %disp(varname)
    112111            copy_variable_data_to_new_model(group_location_in_file,varname, xtype);
    113112        end
    114     catch
     113    catch ME
     114        rethrow(ME)
    115115    end
    116116
     
    141141    global NCData;
    142142    %disp(varname)
    143     % putting try/catch here so that any errors generated while copying data are logged and not lost by the try/catch in walk_nested_groups
    144     try
    145         %disp(netcdf.inqGrpNameFull(group_location_in_file))
    146         %disp(class(netcdf.inqGrpNameFull(group_location_in_file)))
    147         adress_to_attr = strrep(netcdf.inqGrpNameFull(group_location_in_file), '/', '.');
    148         % netcdf uses Row Major Order but MATLAB uses Column Major Order so we need to transpose all arrays w/ more than 1 dim
    149         data = netcdf.getVar(group_location_in_file, netcdf.inqVarID(group_location_in_file, varname));
    150        
    151         if all(size(data)~=1)
    152             data = data.';
     143    % this is an inversion band-aid
     144    if strcmp(varname, 'inversion_class_name')
     145        % we don't need this
     146    else
     147        % putting try/catch here so that any errors generated while copying data are logged and not lost by the try/catch in walk_nested_groups function
     148        try
     149            %disp(netcdf.inqGrpNameFull(group_location_in_file))
     150            %disp(class(netcdf.inqGrpNameFull(group_location_in_file)))
     151            adress_to_attr = strrep(netcdf.inqGrpNameFull(group_location_in_file), '/', '.');
     152           
     153            data = netcdf.getVar(group_location_in_file, netcdf.inqVarID(group_location_in_file, varname));
     154           
     155   
     156            % matlab needs to know that ' ' = char()
     157            if xtype == 2 && isempty(all(data))
     158                data = cell(char());
     159            elseif numel(data) == 1 && xtype == 3 && data == -32767
     160                data = cell(char());
     161            end
     162            % band-aid for cell-char-arrays:
     163            if xtype == 2 && strcmp(data, 'default')
     164                data = {'default'};
     165            end
     166           
     167            % netcdf uses Row Major Order but MATLAB uses Column Major Order so we need to transpose all arrays w/ more than 1 dim
     168            if all(size(data)~=1) || xtype == 2
     169                data = data.';
     170            end
     171           
     172            % the issm c compiler does not work with int64 datatypes, so we need to convert those to int16
     173            % reference this (very hard to find) link for netcdf4 datatypes: https://docs.unidata.ucar.edu/netcdf-c/current/netcdf_8h_source.html
     174            %xtype
     175            if xtype == 10
     176                arg_to_eval = ['model_copy', adress_to_attr, '.', varname, ' = ' , 'double(data);'];
     177                eval(arg_to_eval);
     178                %disp('saved int64 as int16')
     179            else
     180                arg_to_eval = ['model_copy', adress_to_attr, '.', varname, ' = ' , 'data;'];
     181                eval(arg_to_eval);
     182            end
     183           
     184            full_addy = netcdf.inqGrpNameFull(group_location_in_file);
     185            %disp(xtype)
     186            %class(data)
     187            fprintf('Successfully saved %s to %s\n', varname, full_addy);
     188        catch e %e is an MException struct
     189            fprintf(1,'There was an error with %s! \n', varname)
     190            fprintf('The message was:\n%s\n',e.message);
     191            fprintf(1,'The identifier was:\n%s\n',e.identifier);
     192            disp()
     193            % more error handling...
    153194        end
    154        
    155         % the issm c compiler does not work with int64 datatypes, so we need to convert those to int16
    156         % reference this (very hard to find) link for netcdf4 datatypes: https://docs.unidata.ucar.edu/netcdf-c/current/netcdf_8h_source.html
    157         %xtype
    158         if xtype == 10
    159             arg_to_eval = ['model_copy', adress_to_attr, '.', varname, ' = ' , 'double(data);'];
    160             eval(arg_to_eval);
    161             %disp('saved int64 as int16')
    162         else
    163             arg_to_eval = ['model_copy', adress_to_attr, '.', varname, ' = ' , 'data;'];
    164             eval(arg_to_eval);
    165         end
    166        
    167         full_addy = netcdf.inqGrpNameFull(group_location_in_file);
    168         %disp(xtype)
    169         %class(data)
    170         fprintf('Successfully saved %s to %s\n', varname, full_addy);
    171     catch e %e is an MException struct
    172         fprintf(1,'The identifier was:\n%s',e.identifier);
    173         fprintf(1,'There was an error! The message was:\n%s',e.message);
    174         % more error handling...
    175195    end
    176196end
  • TabularUnified issm/trunk/src/m/contrib/musselman/read_netCDF_commit.py

    r27859 r27874  
    2424
    2525def read_netCDF(filename):
    26     print('NetCDF42C v1.1.12')
     26    print('NetCDF42C v1.1.13')
    2727
    2828    # check if path exists
     
    5454    # walk through each group looking for subgroups and variables
    5555    for group in NCData.groups.keys():
    56         # have to send a custom name to this function: filename.groups['group']
    57         name = "NCData.groups['" + str(group) + "']"
    58         walk_nested_groups(name)
     56        if 'debris' in group:
     57            pass
     58        else:
     59            # have to send a custom name to this function: filename.groups['group']
     60            name = "NCData.groups['" + str(group) + "']"
     61            walk_nested_groups(name)
    5962   
     63    print("Model Successfully Recreated.")
    6064    return model_copy
    6165
     
    116120    if str(location_of_variable_in_model + '.' + variable_name) =='results.solutionstep':
    117121        pass
     122    # qmu band-aid
     123    elif 'qmu.statistics.method' in str(location_of_variable_in_model + '.' + variable_name):
     124        pass
    118125    # handle any strings:
    119126    elif 'char' in eval(location_of_variable_in_file + '.dimensions[0]'):
     
    151158
    152159
     160
     161
     162
     163
     164
     165
     166
     167
     168
     169
     170
     171
     172
     173
     174
     175
     176
     177
     178
     179
  • TabularUnified issm/trunk/src/m/contrib/musselman/write_netCDF.m

    r27868 r27874  
    1111
    1212function write_netCDF(model_var, filename)
    13     disp('MATLAB C2NetCDF4 v1.1.12');
     13    disp('MATLAB C2NetCDF4 v1.1.13');
    1414    % model_var = class object to be saved
    1515    % filename = path and name to save file under
     
    3030    try
    3131        % if results had meaningful data, save the name of the subclass and class instance
    32         NetCDF.groups('results');
     32        netcdf.inqNcid(NetCDF,'results');
    3333        results_subclasses_bandaid(model_var);
    3434        % otherwise, ignore
     
    4141
    4242
     43
    4344function make_NetCDF(filename)
     45    % matlab can't handle input in the jupyter interface, so we just yell at the user to rename
     46    % their file if needed
    4447    % If file already exists delete / rename it
    4548    if exist(filename, 'file') == 2
    4649        fprintf('File %s already exists\n', filename);
     50        disp('Please rename your file.')
     51        return
    4752   
    4853        % If so, inquire for a new name or to delete the existing file
    49         newname = input('Give a new name or input "delete" to replace: ', 's');
    50 
    51         if strcmpi(newname, 'delete')
    52             delete(filename);
    53         else
    54             fprintf('New file name is %s\n', newname);
    55             filename = newname;
    56         end
    57     end
    58     % Otherwise create the file and define it globally so other functions can call it
    59     global NetCDF;
    60     NetCDF = netcdf.create(filename, 'NETCDF4');
    61     netcdf.putAtt(NetCDF, netcdf.getConstant('NC_GLOBAL'), 'history', ['Created ', datestr(now)]);
    62     netcdf.defDim(NetCDF, 'Unlim', netcdf.getConstant('NC_UNLIMITED')); % unlimited dimension
    63     netcdf.defDim(NetCDF, 'float', 1);     % single integer dimension
    64     netcdf.defDim(NetCDF, 'int', 1);       % single float dimension
    65    
    66 
    67     fprintf('Successfully created %s\n', filename);
    68 end
    69 
     54        %newname = input('Give a new name or input "delete" to replace: ', 's');
     55
     56        %if strcmpi(newname, 'delete')
     57            %delete filename;
     58        %else
     59            %fprintf('New file name is %s\n', newname);
     60            %filename = newname;
     61        %end
     62    else
     63        % Otherwise create the file and define it globally so other functions can call it
     64        global NetCDF;
     65        NetCDF = netcdf.create(filename, 'NETCDF4');
     66        netcdf.putAtt(NetCDF, netcdf.getConstant('NC_GLOBAL'), 'history', ['Created ', datestr(now)]);
     67        netcdf.defDim(NetCDF, 'Unlim', netcdf.getConstant('NC_UNLIMITED')); % unlimited dimension
     68        netcdf.defDim(NetCDF, 'float', 1);     % single integer dimension
     69        netcdf.defDim(NetCDF, 'int', 1);       % single float dimension
     70   
     71        fprintf('Successfully created %s\n', filename);
     72    end
     73end
     74
     75
     76%{
     77    Since python uses subclass instances and MATLAB uses fields, we need to guess which subclass instance python will need
     78    given the name of the sub-field in MATLAB. We make this guess based on the name of the MATLAB subfield that will contain
     79    the name of the python subclass instance. For example, md.results.StressbalanceSolution is an subfield in MATLAB,
     80    but a class instance of solution(). Notice that StressbalanceSolution contains the name "Solution" in it. This is what
     81    we will save to the netCDF file for python to pick up.
     82%}
    7083
    7184function results_subclasses_bandaid(model_var)
    72     % Since the results class may have nested classes within it,
    73     % we need to record the name of the nested class instance variable as it appears in the model that we're trying to save
     85    global NetCDF;
     86    % The results class may have nested fields within it, so we need to record the name of
     87    % the nested field as it appears in the model that we're trying to save
    7488    quality_control = {};
    7589   
     
    86100        class_instance_name = class_instance_names{i};
    87101       
    88         % Check to see which class its from and record that info in the NetCDF to recreate structure later
    89102        % Check to see if there is a solutionstep class instance
    90         if isa(results_var.(class_instance_name), 'solutionstep')
     103        if contains(class_instance_name, 'solutionstep',IgnoreCase=true)
    91104            quality_control{end+1} = 1;
    92             write_string_to_netcdf('variable_name', 'solutionstep', 'address_of_child', class_instance_name, 'group', groupid);
     105            write_string_to_netcdf('solutionstep', class_instance_name, groupid);
     106            disp('Successfully stored class python subclass instance: solutionstep')
    93107        end
    94108       
    95109        % Check to see if there is a solution class instance
    96         if isa(results_var.(class_instance_name), 'solution')
     110        if contains(class_instance_name, 'solution',IgnoreCase=true)
    97111            quality_control{end+1} = 1;
    98             write_string_to_netcdf('variable_name', 'solution', 'address_of_child', class_instance_name, 'group', groupid);
     112            write_string_to_netcdf('solution', class_instance_name, groupid);
     113            disp('Successfully stored class python subclass instance: solution')
    99114        end
    100115       
    101116        % Check to see if there is a resultsdakota class instance
    102         if isa(results_var.(class_instance_name), 'resultsdakota')
     117        if contains(class_instance_name, 'resultsdakota',IgnoreCase=true)
    103118            quality_control{end+1} = 1;
    104             write_string_to_netcdf('variable_name', 'resultsdakota', 'address_of_child', class_instance_name, 'group', groupid);
     119            write_string_to_netcdf('resultsdakota', class_instance_name, groupid);
     120            disp('Successfully stored class python subclass instance: resultsdakota')
    105121        end
    106122    end
     
    137153    % model_subclass is an object (ie, md.mesh.elements)
    138154    % list_of_layers is a cell array of subclasses/attributes/fields so that we can copy the structure into netcdf (ie, {'mesh', 'elements'})
    139     % Use try/except since model_subclass is either a subclass w/ fields or it's not, no unknown exceptions
     155    % need to check if inversion or m1qn3inversion or taoinversion class
     156    if numel(given_list_of_layers) == 1
     157        if strcmp(given_list_of_layers{1}, 'inversion')
     158            create_group(model_subclass, given_list_of_layers);
     159            check_inversion_class(model_subclass);
     160        end
     161    end
     162   
     163    % Use try/except since model_subclass is either a subclass/struct w/ props/fields or it's not, no unknown exceptions
    140164    try
    141165        % look for children - this is where the catch would be called
    142166        children = fieldnames(model_subclass);
     167
     168        % if there are children, loop through them and see if we need to save any data
    143169        for child = 1:numel(children)
    144170            % record our current location
     
    151177           
    152178            % if the empty model does not have this attribute, it's because it's new so we save it to netcdf
    153             try
    154                 location_of_child_in_empty_model = empty_model_subclass.(current_child);
    155             catch
    156                 % empty model didn't have the attr, so we save it to netcdf
    157                 create_group(location_of_child, list_of_layers);
    158             end
    159            
    160             % if the current attribute is a numerical array assume it has valuable data that needs to be saved
    161             if isnumeric(location_of_child) && logical(numel(location_of_child) > 1)
    162                 create_group(location_of_child, list_of_layers);
    163                 % i don't think I need this line but it's in my python code...
    164                 % walk_through_subclasses(location_of_child)
    165             % if the attributes are identical we don't need to save anything
    166             elseif (all(isnan(location_of_child)) && all(isnan(location_of_child_in_empty_model))) || isempty(setxor(location_of_child, location_of_child_in_empty_model))
    167                 walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
    168             % if the attributes are not the same we need to save ours
    169             else
    170                 create_group(location_of_child, list_of_layers);
    171                 walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
     179            % there are 2 cases: the location is a struct, the location is a class
     180            if isstruct(model_subclass)
     181                % this would mean that the layer above the layer we're interested in is a struct, so
     182                % we can navigate our empty model as such
     183                if isfield(empty_model_subclass, current_child)
     184                    % the layer we're interested in does exist, we just need to compare states
     185                    location_of_child_in_empty_model = empty_model_subclass.(current_child);
     186                    % if the current attribute is a numerical array assume it has valuable data that needs to be saved
     187                    if isnumeric(location_of_child) && logical(numel(location_of_child) > 1)
     188                        create_group(location_of_child, list_of_layers);
     189                    % if the attributes are identical we don't need to save anything
     190                    elseif (all(isnan(location_of_child)) && all(isnan(location_of_child_in_empty_model))) || isempty(setxor(location_of_child, location_of_child_in_empty_model))
     191                        walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
     192                    % if the attributes are not the same we need to save ours
     193                    else
     194                        % THE ORDER OF THESE LINES IS CRITICAL
     195                        walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
     196                        create_group(location_of_child, list_of_layers);
     197                    end
     198                % this would mean that the layer we're interested in is not fundamental to the model architecture
     199                % and thus needs to be saved to the netcdf
     200                else
     201                    walk_through_subclasses(location_of_child, empty_model_subclass, list_of_layers);
     202                    create_group(location_of_child, list_of_layers);
     203                end
     204            % this would mean it's not a struct, and must be a class/subclass
     205            % we now check the state of the class property
     206            else
     207                try
     208                    if isprop(empty_model_subclass, current_child)
     209                        % the layer we're interested in does exist, we just need to compare states
     210                        location_of_child_in_empty_model = empty_model_subclass.(current_child);
     211                        % if the current attribute is a numerical array assume it has valuable data that needs to be saved
     212                        if isnumeric(location_of_child) && logical(numel(location_of_child) > 1)
     213                            create_group(location_of_child, list_of_layers);
     214                       
     215                        elseif iscell(location_of_child)
     216                            % if the attributes are identical we don't need to save anything
     217                            if isempty(setxor(location_of_child, location_of_child_in_empty_model))
     218                                % pass
     219                            else
     220                            % otherwise we need to save
     221                                walk_through_subclasses(location_of_child, empty_model_subclass, list_of_layers);
     222                                create_group(location_of_child, list_of_layers);
     223                            end
     224                        elseif (all(isnan(location_of_child)) && all(isnan(location_of_child_in_empty_model)))
     225                            walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
     226                        % if the attributes are not the same we need to save ours
     227                        else
     228                            % THE ORDER OF THESE LINES IS CRITICAL
     229                            walk_through_subclasses(location_of_child, location_of_child_in_empty_model, list_of_layers);
     230                            create_group(location_of_child, list_of_layers);
     231                        end
     232                    else
     233                        walk_through_subclasses(location_of_child, empty_model_subclass, list_of_layers);
     234                        create_group(location_of_child, list_of_layers);
     235                    end
     236                catch
     237                    walk_through_subclasses(location_of_child, empty_model_subclass, list_of_layers);
     238                    create_group(location_of_child, list_of_layers);
     239                end
    172240            end
    173241        end
     
    175243        % If the caught error is a fieldname error, it's just saying that a variable has no fields and thus can be ignored
    176244        if strcmp(ME.identifier, 'MATLAB:fieldnames:InvalidInput')
     245            % do nothing
    177246        % this is if we come accross instances/subfields in our model that are not fundamental to the model class (ie, taoinversion)
    178247        elseif strcmp(ME.identifier, 'MATLAB:UndefinedFunction')
     248            walk_through_subclasses(location_of_child, empty_model_subclass, given_list_of_layers);
     249            create_group(location_of_child, list_of_layers);
    179250        % If it's a different error, rethrow it to MATLAB's default error handling
    180251        else
     252            disp(ME.identifier)
     253            disp(given_list_of_layers)
    181254            rethrow(ME);
    182255        end
     
    196269        group = netcdf.defGrp(NetCDF, group_name);
    197270    catch % group was already made
    198         group = netcdf.inqNcid(NetCDF, group_name);
    199     end
    200     % need to check if inversion or m1qn3inversion or taoinversion class
    201     if strcmp(group_name, 'inversion')
    202         check_inversion_class(location_of_child);
    203     end
    204    
     271        group = netcdf.inqNcid(NetCDF, group_name);   
     272    end
     273
    205274    % if the data is nested, create nested groups to match class structure
    206275    if numel(list_of_layers) > 2
    207         for name = list_of_layers{2:end-1}
    208             % again, the group levels may have already been made
     276        % the string() method is really important here since matlab apparently can't handle the infinite complexity of a string without the string method.
     277        for name = string(list_of_layers(2:end-1))
     278            % the group levels may have already been made
    209279            try % group hasn't been made
    210280                group = netcdf.defGrp(group, name);
     
    214284        end
    215285    end
    216 
    217     % Lastly, handle the variable(s)
    218     variable_name = list_of_layers{end};
    219     create_var(variable_name, location_of_child, group);
    220    
    221 end
    222 
    223 
    224 
     286    % if the object is not a variable, we have nothing to save
     287    try
     288        % if this line works, we're still dealing with a struct and need lower levels
     289        if isempty(fieldnames(location_of_child))
     290            % do nothing
     291        end
     292    catch
     293        % if that line doesn't work, it means we're dealing with data
     294        % Lastly, handle the variable(s)
     295        variable_name = list_of_layers{end};
     296        create_var(variable_name, location_of_child, group);
     297    end
     298end
     299
     300
     301% ironically inversion does not have the same problem as results as inversion subfields
     302% are actually subclasses and not fields
    225303function check_inversion_class(model_var)
    226304    global NetCDF;
     
    229307    % Check if the function has already been executed
    230308    if isempty(executed)
     309        disp('Deconstructing Inversion class instance')
    231310        % Need to make sure that we have the right inversion class: inversion, m1qn3inversion, taoinversion
    232311        groupid = netcdf.inqNcid(NetCDF,'inversion');
     
    234313        if isa(model_var, 'm1qn3inversion')
    235314            write_string_to_netcdf('inversion_class_name', 'm1qn3inversion', groupid);
    236             disp('Successfully saved inversion class instance m1qn3inversion');
     315            disp('Successfully saved inversion class instance m1qn3inversion')
    237316        elseif isa(model_var, 'taoinversion')
    238317            write_string_to_netcdf('inversion_class_name', 'taoinversion', groupid);
    239             disp('Successfully saved inversion class instance taoinversion');
     318            disp('Successfully saved inversion class instance taoinversion')
    240319        else
    241320            write_string_to_netcdf('inversion_class_name', 'inversion', groupid);
    242             disp('Successfully saved inversion class instance inversion');
     321            disp('Successfully saved inversion class instance inversion')
    243322        end
    244323        % Set the persistent variable to indicate that the function has been executed
    245324        executed = true;
    246     else
    247         % Code to skip execution if the function has already run
    248     end
    249 
    250 
     325    end
    251326end
    252327
     
    265340    if any(size(address_of_child)>1) && ~ischar(address_of_child)
    266341        write_numeric_array_to_netcdf(variable_name, address_of_child, group);
    267    
    268     % check if it's an int
    269     elseif mod(address_of_child,1) == 0 || isinteger(address_of_child) && numel(address_of_child) == 1
     342
     343    % check if it's a string
     344    elseif ischar(address_of_child)
     345        write_string_to_netcdf(variable_name, address_of_child, group);
     346
     347    % or an empty variable
     348    elseif isempty(address_of_child)
     349        variable = netcdf.defVar(group, variable_name, "NC_DOUBLE", intdim);
     350
     351    % or a list of strings -- this needs work as it can only handle a list of 1 string
     352    elseif iscell(address_of_child) && ischar(address_of_child{1})
     353        for i = 1:numel(address_of_child)
     354            write_string_to_netcdf(variable_name, address_of_child{i}, group, true);
     355        end
     356       
     357    % or an empty list
     358    elseif iscell(address_of_child) && isempty(address_of_child) || isa(address_of_child, 'double') && isempty(address_of_child)
    270359        variable = netcdf.defVar(group, variable_name, "NC_INT", intdim);
     360        netcdf.putVar(group,variable, -32767);
     361
     362    % or a bool
     363    elseif islogical(address_of_child)
     364        % netcdf4 can't handle bool types like true/false so we convert all to int 1/0 and add an attribute named units with value 'bool'
     365        variable = netcdf.defVar(group, variable_name, 'NC_SHORT', intdim);
     366        netcdf.putVar(group,variable,int8(address_of_child));
     367        % make sure other systems can flag the bool type
     368        netcdf.putAtt(group,variable,'units','bool');
     369
     370    % or a regular list
     371    elseif iscell(address_of_child)
     372        disp('made list w/ unlim dim')
     373        variable = netcdf.defVar(group, variable_name, "NC_DOUBLE", unlimdim);
    271374        netcdf.putVar(group,variable,address_of_child);
    272    
     375       
    273376    % or a float
    274377    elseif isfloat(address_of_child) && numel(address_of_child) == 1
    275378        variable = netcdf.defVar(group, variable_name, "NC_DOUBLE", floatdim);
    276379        netcdf.putVar(group,variable,address_of_child);
    277 
    278     % or a string
    279     elseif ischar(address_of_child)
    280         write_string_to_netcdf(variable_name, address_of_child, group);
    281 
    282     % or a bool
    283     elseif islogical(address_of_child)
    284         % netcdf4 can't handle bool types like true/false so we convert all to int 1/0 and add an attribute named units with value 'bool'
    285         variable = netcdf.defVar(group, variable_name, 'NC_SHORT', 'int');
    286         netcdf.putVar(group,variable,logical(address_of_child));
    287         % make sure other systems can flag the bool type
    288         netcdf.putAtt(group,variable,'units','bool');
    289        
    290     % or an empty list
    291     elseif iscell(address_of_child) && isempty(address_of_child) || isa(address_of_child, 'double') && isempty(address_of_child)
     380       
     381    % or a int
     382    elseif mod(address_of_child,1) == 0 || isinteger(address_of_child) && numel(address_of_child) == 1
    292383        variable = netcdf.defVar(group, variable_name, "NC_SHORT", intdim);
    293 
    294     % or a list of strings -- this needs work as it can only handle a list of 1 string
    295     elseif iscell(address_of_child) && ischar(address_of_child{1})
    296         for i = 1:numel(address_of_child)
    297             write_string_to_netcdf(variable_name, address_of_child{i}, group, list = true);
    298         end
    299 
    300     % or a regular list
    301     elseif iscell(address_of_child)
    302         disp('made list w/ unlim dim')
    303         variable = netcdf.defVar(group, variable_name, "NC_DOUBLE", unlimdim);
    304384        netcdf.putVar(group,variable,address_of_child);
    305385
     
    331411    the_string_to_save = address_of_child;
    332412
    333     % convert string to
    334     uint_method=uint8(the_string_to_save);
    335     method_ID = char(uint_method);
    336     length_of_the_string = numel(method_ID);
    337    
    338     % Convert the string to character data using string array
    339     %str_out = char(the_string_to_save)
    340 
    341     % Determine the length of the string
    342     %length_of_the_string = numel(str_out)
    343 
    344     % Check if the dimension already exists, and if not, create it
    345     name_of_dimension = ['char', num2str(length_of_the_string)];
    346     try
    347         dimID = netcdf.defDim(group, name_of_dimension, length_of_the_string);
    348     catch
    349         dimID = netcdf.inqDimID(group, name_of_dimension);
    350     end
    351     % Now we can make a variable in this dimension:
    352     string_var = netcdf.defVar(group, variable_name, "NC_CHAR", [dimID]);
    353    
    354     % Finally, we can write the variable:
    355     netcdf.putVar(group, string_var, method_ID);
     413    if isempty(the_string_to_save)
     414        % if the char array is empty, save an empty char
     415        name_of_dimension = ['char', num2str(0)];
     416        try
     417            dimID = netcdf.defDim(group, name_of_dimension, 0);
     418        catch
     419            dimID = netcdf.inqDimID(group, name_of_dimension);
     420        end
     421        % Now we can make a variable in this dimension:
     422        string_var = netcdf.defVar(group, variable_name, "NC_CHAR", [dimID]);
     423        % we leave empty now
     424    else
     425        % convert string to
     426        uint_method=uint8(the_string_to_save).';
     427        method_ID = char(uint_method);
     428        length_of_the_string = numel(method_ID);
     429       
     430        % Convert the string to character data using string array
     431        %str_out = char(the_string_to_save)
     432   
     433        % Determine the length of the string
     434        %length_of_the_string = numel(str_out)
     435   
     436        % Check if the dimension already exists, and if not, create it
     437        name_of_dimension = ['char', num2str(length_of_the_string)];
     438        try
     439            dimID = netcdf.defDim(group, name_of_dimension, length_of_the_string);
     440        catch
     441            dimID = netcdf.inqDimID(group, name_of_dimension);
     442        end
     443        % Now we can make a variable in this dimension:
     444        string_var = netcdf.defVar(group, variable_name, "NC_CHAR", [dimID]);
     445        % Finally, we can write the variable (always transpose for matlab):
     446        netcdf.putVar(group, string_var, method_ID);
     447    end
    356448
    357449    disp(['Successfully transferred data from ', variable_name, ' to the NetCDF']);
     
    463555    end
    464556end
    465 
  • TabularUnified issm/trunk/src/m/contrib/musselman/write_netCDF_commit.py

    r27859 r27874  
    2424
    2525def write_netCDF(model_var, model_name: str, filename: str):
    26     print('C2NetCDF4 v1.1.12')
     26    print('Python C2NetCDF4 v1.1.12')
    2727    '''
    2828    model_var = class object to be saved
     
    9090   
    9191        # If so, inqure for a new name or to do delete the existing file
    92         newname = input('Give a new name or input "delete" to replace: ')
     92        newname = input('Give a new name or "delete" to replace: ')
    9393
    9494        if newname == 'delete':
     
    134134            # in the framework of an empty model. If this is the case, we move to the except statement
    135135            try:
    136                 # if the variable is an array, assume it has relevant data
     136                # if the variable is an array, assume it has relevant data (this is because the next line cannot evaluate "==" with an array)
    137137                if isinstance(eval(adress_of_child), np.ndarray):
    138138                    create_group(model_var, adress_of_child)
    139                     walk_through_subclasses(model_var, adress_of_child, model_name)
     139                # if the attributes are identical we don't need to save anything
    140140                elif eval(adress_of_child) == eval(adress_of_child_in_empty_class):
    141141                    walk_through_subclasses(model_var, adress_of_child, model_name)
     
    144144                    create_group(model_var, adress_of_child)
    145145                    walk_through_subclasses(model_var, adress_of_child, model_name)
     146            # AttributeError since the empty_model wouldn't have the same attribute as our model
    146147            except AttributeError:
     148                # THE ORDER OF THESE LINES IS CRITICAL
     149                walk_through_subclasses(model_var, adress_of_child, model_name)
    147150                create_group(model_var, adress_of_child)
    148                 walk_through_subclasses(model_var, adress_of_child, model_name)
    149151    except AttributeError: pass
    150152    except Exception as e: print(e)
     
    166168
    167169    # if the data is nested, create nested groups to match class structure
    168     if len(levels_of_class) > 3:
     170    if len(levels_of_class) > 2:
    169171        for name in levels_of_class[2:-1]:
    170172            group = group.createGroup(str(name))
     
    349351            # write the variable:
    350352            variable[:] = eval(adress_of_child)
     353
     354
     355
     356
     357
     358
     359
     360
     361
     362
     363
     364
     365
     366
     367
     368
     369
     370
     371
     372
     373
     374
     375
     376
     377
     378
     379
     380
     381
     382
     383
     384
     385
Note: See TracChangeset for help on using the changeset viewer.