Changeset 27896 for issm/trunk


Ignore:
Timestamp:
09/05/23 15:48:58 (19 months ago)
Author:
musselman
Message:

Updated read_netCDF.py to include functionality for arrays of objects saved from MATLAB.

File:
1 edited

Legend:

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

    r27889 r27896  
    1010from taoinversion import taoinversion
    1111from collections import OrderedDict
     12import sys
     13from massfluxatgate import massfluxatgate
     14
    1215
    1316
     
    117120
    118121    for variable in eval(group_location_in_file + '.variables.keys()'):
    119         if variable == 'this_is_a_nested' and 'results' in group_location_in_file:
    120             # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']'
    121             pattern = r"\['(.*?)'\]"
    122             matches = re.findall(pattern, group_location_in_file)
    123             name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']")
    124             copy_multidimensional_results_struct(group_location_in_file, name_of_struct, NCData)
    125             istruct = True
    126 
    127         elif variable == 'this_is_a_nested' and 'qmu' in group_location_in_file:
    128             print('encountered qmu structure that is not yet supported.')
    129             # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']'
    130             #pattern = r"\['(.*?)'\]"
    131             #matches = re.findall(pattern, group_location_in_file)
    132             #name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']")
    133             #name_of_struct = eval(group_location_in_file + ".variables['']")
    134             #copy_multidimensional_qmu_struct(group_location_in_file, name_of_struct)
    135             isstruct = True
    136    
    137         else:
    138             location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']"
    139             # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1']
    140             # Define the regex pattern to match the groups within brackets
    141             pattern = r"\['(.*?)'\]"
    142             # Use regex to find all matches and return something like 'group1.group1.1.group1.1.1 ...' where the last value is the name of the variable
    143             matches = re.findall(pattern, location_of_variable_in_file)
    144             variable_name = matches[-1]
    145             location_of_variable_in_model = '.'.join(matches[:-1])
    146             copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose=verbose)
    147            
    148     if 'istruct' in locals():
     122        if 'is_object' not in locals():
     123            if variable == 'this_is_a_nested' and 'results' in group_location_in_file and 'qmu' not in group_location_in_file:
     124                # have to do some string deconstruction to get the name of the class instance/last group from 'NetCDF.groups['group1'].groups['group1.1']'
     125                pattern = r"\['(.*?)'\]"
     126                matches = re.findall(pattern, group_location_in_file)
     127                name_of_struct = matches[-1] #eval(group_location_in_file + ".variables['solution']")
     128                copy_multidimensional_results_struct(group_location_in_file, name_of_struct, NCData)
     129                is_object = True
     130   
     131            elif variable == 'name_of_cell_array':
     132                # reconstruct an array of elements
     133                copy_cell_array_of_objects(group_location_in_file, model_copy, NCData, verbose)
     134                is_object = True
     135   
     136            elif variable == 'this_is_a_nested' and 'qmu' in group_location_in_file:
     137                if verbose:
     138                    print('encountered qmu structure that is not yet supported.')
     139                else: pass
     140                   
     141                is_object = True
     142       
     143            else:
     144                location_of_variable_in_file = group_location_in_file + ".variables['" + str(variable) + "']"
     145                # group_location_in_file is like filename.groups['group1'].groups['group1.1'].groups['group1.1.1']
     146                # Define the regex pattern to match the groups within brackets
     147                pattern = r"\['(.*?)'\]"
     148                # Use regex to find all matches and return something like 'group1.group1.1.group1.1.1 ...' where the last value is the name of the variable
     149                matches = re.findall(pattern, location_of_variable_in_file)
     150                variable_name = matches[-1]
     151                location_of_variable_in_model = '.'.join(matches[:-1])
     152                copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose=verbose)
     153
     154    # if one of the variables above was an object, further subclasses will be taken care of when reconstructing it
     155    if 'is_object' in locals():
    149156        pass
    150157    else:
     
    152159            new_nested_group = group_location_in_file + ".groups['" + str(nested_group) + "']"
    153160            walk_nested_groups(new_nested_group, NCData, verbose=verbose)
     161
     162
     163def copy_cell_array_of_objects(group_location_in_file, model_copy, NCData, verbose):
     164    '''
     165        The structure in netcdf for groups with the name_of_cell_array variable is like:
     166
     167        group: 2x6_cell_array_of_objects {
     168            name_of_cell_array = <name_of_cell_array>
     169
     170            group: Row_1_of_2 {
     171                group: Col_1_of_6 {
     172                    ... other groups can be here that refer to objects
     173                } // group Col_6_of_6
     174            } // group Row_1_of_2
     175
     176            group: Row_2_of_2 {
     177                group: Col_1_of_6 {
     178                    ... other groups can be here that refer to objects
     179                } // group Col_6_of_6
     180            } // group Row_2_of_2
     181        } // group 2x6_cell_array_of_objects
     182
     183        We have to navigate this structure to extract all the data and recreate the
     184        original structure when the model was saved
     185    '''
     186
     187    # get the name_of_cell_array, rows and cols vars
     188    name_of_cell_array_varID = eval(group_location_in_file + ".variables['name_of_cell_array']")
     189    rows_varID = eval(group_location_in_file + ".variables['rows']")
     190    cols_varID = eval(group_location_in_file + ".variables['cols']")
     191
     192    name_of_cell_array = name_of_cell_array_varID[:][...].tobytes().decode()
     193    rows = rows_varID[:]
     194    cols = cols_varID[:]
     195
     196    # now we work backwards: make the array, fill it in, and assign it to the model
     197
     198    # make the array
     199    array = list()
     200
     201    subgroups = eval(group_location_in_file + ".groups") #.keys()")
     202
     203    # enter each subgroup, get the data, assign it to the corresponding index of cell array
     204    if rows > 1:
     205        # we go over rows
     206        # set index for rows
     207        row_idx = 0
     208        for row in list(subgroups):
     209            # make list for each row
     210            current_row = list()
     211            columns = subgroups[str(row)].groups.keys()
     212
     213            # set index for columns
     214            col_idx = 0
     215
     216            # iterate over columns
     217            for col in list(columns):
     218                # now get the variables
     219                current_col_vars = columns.groups[str(col)].variables
     220
     221                # check for special datastructures               
     222                if "class_is_a" in current_col_vars:
     223                    class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode()
     224                    col_data = deserialize_class(class_name, columns.groups[str(col)], NCData, verbose)
     225                    is_object = True
     226                elif "this_is_a_nested" in current_col_vars:
     227                    # functionality not yet supported
     228                    print('Error: Cell Arrays of structs not yet supported!')
     229                    is_object = True
     230                else:
     231                    if 'is_object_' in locals():
     232                        pass
     233                        # already taken care of
     234                    else:
     235                        # store the variables as normal -- to be added later
     236                        print('Error: Arrays of mixed objects not yet supported!')
     237                        for var in current_col_vars:
     238                            # this is where that functionality would be handled
     239                            pass
     240                col_idx += 1
     241                # add the entry to our row list
     242                current_row.append(col_data)
     243
     244            # add the list of columns to the array
     245            array.append(current_row)
     246            row_idx += 1
     247
     248    else:
     249        # set index for columns
     250        col_idx = 0
     251
     252        # iterate over columns
     253        for col in list(subgroups):
     254            # now get the variables
     255            current_col_vars = subgroups[str(col)].variables
     256           
     257            # check for special datastructures
     258            if "class_is_a" in current_col_vars:
     259                class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode()
     260                col_data = deserialize_class(class_name, subgroups[str(col)], NCData, verbose)
     261                is_object = True
     262            elif "this_is_a_nested" in current_col_vars:
     263                # functionality not yet supported
     264                print('Error: Cell Arrays of structs not yet supported!')
     265                is_object = True
     266            else:
     267                if 'is_object_' in locals():
     268                    pass
     269                    # already taken care of
     270                else:
     271                    # store the variables as normal -- to be added later
     272                    print('Error: Arrays of mixed objects not yet supported!')
     273                    for var in current_col_vars:
     274                        # this is where that functionality would be handled
     275                        pass
     276            col_idx += 1
     277            # add the list of columns to the array
     278            array.append(col_data)
     279
     280    # finally, add the attribute to the model
     281    # borrow some code from above:
     282    pattern = r"\['(.*?)'\]"
     283    matches = re.findall(pattern, group_location_in_file)
     284    variable_name = matches[0]
     285    setattr(model_copy.__dict__[variable_name], name_of_cell_array, array)
     286
     287
     288
     289def deserialize_class(class_name, group, NCData, verbose=False):
     290
     291    # most ISSM classes are imported by from <name> import <name>
     292    class ModuleError(Exception):
     293        pass
     294   
     295    if class_name not in sys.modules:
     296        raise ModuleError(str('Model requires the following class to be imported from a module: ' + class_name + ". Please add the import to read_netCDF.py in order to continue."))
     297
     298    # Instantiate the class
     299    class_instance = eval(class_name + "()")
     300
     301    # Get and assign properties
     302    subgroups = list(group.groups.keys())
     303
     304    if len(subgroups) == 1:
     305        # Get properties
     306        subgroup = group[subgroups[0]]
     307        varIDs = subgroup.variables.keys()
     308        for varname in varIDs:
     309            # Variable metadata
     310            var = subgroup[varname]
     311
     312            # Data
     313            if 'char' in var.dimensions[0]:
     314                data = var[:][...].tobytes().decode()
     315            else:
     316                data = var[:]
     317
     318            # Some classes may have permissions, so we skip those
     319            try:
     320                setattr(class_instance, varname, data)
     321            except:
     322                pass
     323    else:
     324        # Not supported
     325        pass
     326       
     327    return class_instance
    154328
    155329
     
    208382    try:
    209383        # results band-aid...
    210         #print(str(location_of_variable_in_model + '.' + variable_name))
    211384        if str(location_of_variable_in_model + '.' + variable_name) in ['results.solutionstep', 'results.solution', 'results.resultsdakota']:
    212385            pass
     
    240413                    else:
    241414                        # we have to convert numpy datatypes to native python types with .item()
    242                         setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item())                       
     415                        setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item())
    243416            except:
    244                     setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
     417                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
    245418    except AttributeError:
    246419        copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose=verbose)
     
    248421    if verbose:
    249422        print('Successfully loaded ' + location_of_variable_in_model + '.' + variable_name + ' into model.')
     423
    250424
    251425
Note: See TracChangeset for help on using the changeset viewer.