Changeset 27898 for issm/trunk


Ignore:
Timestamp:
09/06/23 14:41:22 (19 months ago)
Author:
musselman
Message:

Added functionality for lists (arrays) of objects in python for read/write_NetCDF.py files.

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

Legend:

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

    r27896 r27898  
    3030        print('NetCDF42C v1.1.13')
    3131
    32     # check if path exists
    33     if path.exists(filename):
     32    # this is a precaution so that data is not lost
     33    try:
     34        # check if path exists
     35        if path.exists(filename):
     36            if verbose:
     37                print('Opening {} for reading'.format(filename))
     38            else: pass
     39   
     40            # open the given netCDF4 file
     41            NCData = Dataset(filename, 'r')
     42            # remove masks from numpy arrays for easy conversion
     43            NCData.set_auto_mask(False)
     44        else:
     45            print('The file you entered does not exist or cannot be found in the current directory')
     46            return print()
     47       
     48        # continuation of band-aid for results class
     49        try:
     50            NCData.groups['results']
     51            make_results_subclasses(NCData, verbose)
     52        except:
     53            pass
     54   
     55        # similarly, we need to check and see if we have an m1qn3inversion class instance
     56        try:
     57            NCData.groups['inversion']
     58            check_inversion_class(NCData, verbose)
     59        except:
     60            pass
     61       
     62        # walk through each group looking for subgroups and variables
     63        for group in NCData.groups.keys():
     64            if 'debris' in group:
     65                pass
     66            else:
     67                # have to send a custom name to this function: filename.groups['group']
     68                name = "NCData.groups['" + str(group) + "']"
     69                walk_nested_groups(name, NCData, verbose)
     70       
    3471        if verbose:
    35             print('Opening {} for reading'.format(filename))
    36         else: pass
    37 
    38         # open the given netCDF4 file
    39         NCData = Dataset(filename, 'r')
    40         # remove masks from numpy arrays for easy conversion
    41         NCData.set_auto_mask(False)
    42     else:
    43         print('The file you entered does not exist or cannot be found in the current directory')
    44         return print()
    45    
    46     # continuation of band-aid for results class
    47     try:
    48         NCData.groups['results']
    49         make_results_subclasses(NCData, verbose)
    50     except:
    51         pass
    52 
    53     # similarly, we need to check and see if we have an m1qn3inversion class instance
    54     try:
    55         NCData.groups['inversion']
    56         check_inversion_class(NCData, verbose)
    57     except:
    58         pass
    59    
    60     # walk through each group looking for subgroups and variables
    61     for group in NCData.groups.keys():
    62         if 'debris' in group:
    63             pass
    64         else:
    65             # have to send a custom name to this function: filename.groups['group']
    66             name = "NCData.groups['" + str(group) + "']"
    67             walk_nested_groups(name, NCData, verbose)
    68    
    69     if verbose:
    70         print("Model Successfully Loaded.")
    71     return model_copy
     72            print("Model Successfully Loaded.")
     73           
     74        NCData.close()
     75       
     76        return model_copy
     77
     78    except Error:
     79        NCData.close()
     80        return Error
    7281
    7382
     
    126135                matches = re.findall(pattern, group_location_in_file)
    127136                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)
     137                deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData)
    129138                is_object = True
    130139   
    131140            elif variable == 'name_of_cell_array':
    132141                # reconstruct an array of elements
    133                 copy_cell_array_of_objects(group_location_in_file, model_copy, NCData, verbose)
     142                deserialize_array_of_objects(group_location_in_file, model_copy, NCData, verbose)
    134143                is_object = True
    135144   
     
    150159                variable_name = matches[-1]
    151160                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)
     161                deserialize_data(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose=verbose)
    153162
    154163    # if one of the variables above was an object, further subclasses will be taken care of when reconstructing it
     
    161170
    162171
    163 def copy_cell_array_of_objects(group_location_in_file, model_copy, NCData, verbose):
     172def deserialize_array_of_objects(group_location_in_file, model_copy, NCData, verbose):
    164173    '''
    165174        The structure in netcdf for groups with the name_of_cell_array variable is like:
     
    336345'''
    337346
    338 def copy_multidimensional_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False):
     347def deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False):
    339348    '''
    340349    A common multidimensional array is the 1xn md.results.TransientSolution object.
     
    376385
    377386
    378 def copy_variable_data_to_new_model(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose = False):
     387def deserialize_data(location_of_variable_in_file, location_of_variable_in_model, variable_name, NCData, verbose = False):
    379388    # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file
    380389    # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those
     
    417426                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
    418427    except AttributeError:
    419         copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose=verbose)
     428        deserialize_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose=verbose)
    420429
    421430    if verbose:
     
    424433
    425434
    426 def copy_variable_data_to_new_model_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose = False):
     435def deserialize_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose = False):
    427436    # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file
    428437
  • issm/trunk/src/m/contrib/musselman/write_netCDF.py

    r27889 r27898  
    11# imports
    2 import netCDF4
    3 from netCDF4 import Dataset
     2import NCData4
     3from NCData4 import Dataset
    44import numpy as np
    55import numpy.ma as ma
     
    1515'''
    1616Given a md, this set of functions will perform the following:
    17     1. Enter each nested class of the md.
    18     2. View each attribute of each nested class.
    19     3. Compare state of attribute in the model to an empty model class.
    20     4. If states are identical, pass.
    21     5. Otherwise, create nested groups named after class structure.
    22     6. Create variable named after class attribute and assign value to it.
     17    1. View each attribute of each nested class.
     18    2. Compare state of attribute in the model to an empty model.
     19    3. If states are identical, pass. (except for np arrays which will always be saved)
     20    4. Otherwise, create nested groups named after class structure.
     21    5. Create variable named after class attribute and assign value to it.
    2322'''
    2423
    2524
    26 def write_netCDF(md, filename: str, verbose = False):
     25def write_NCData(md, filename: str, verbose = False):
    2726    if verbose:
    28         print('Python C2NetCDF4 v1.1.14')
     27        print('Python C2NCData4 v1.1.14')
    2928    else: pass
    3029    '''
     
    3332    verbose = T/F muted or show log statements. Naturally muted
    3433    '''
    35    
    36     # Create a NetCDF file to write to
    37     NetCDF = make_NetCDF(filename, verbose)
    38    
    39     # Create an instance of an empty md class to compare md_var against
    40     empty_model = model()
    41 
    42     # Walk through the md class and compare subclass states to empty_model
    43     walk_through_model(md, empty_model, NetCDF, verbose)
    44 
    45     # in order to handle some subclasses in the results class, we have to utilize this band-aid
    46     # there will likely be more band-aids added unless a class name library is created with all class names that might be added to a md
     34    # this is a precaution so that data is not lost
    4735    try:
    48         # if results has meaningful data, save the name of the subclass and class instance
    49         NetCDF.groups['results']
    50         results_subclasses_bandaid(md, NetCDF, verbose)
    51         # otherwise, ignore
    52     except KeyError:
    53         pass
     36        # Create a NCData file to write to
     37        NCData = create_NCData(filename, verbose)
    5438       
    55     NetCDF.close()
    56     if verbose:
    57         print('Model successfully saved as NetCDF4')
    58     else: pass
    59    
    60 
    61 def results_subclasses_bandaid(md, NetCDF, verbose = False):
     39        # Create an instance of an empty md class to compare md_var against
     40        empty_model = model()
     41   
     42        # Walk through the md class and compare subclass states to empty_model
     43        walk_through_model(md, empty_model, NCData, verbose)
     44   
     45        # in order to handle some subclasses in the results class, we have to utilize this band-aid
     46        # there will likely be more band-aids added unless a class name library is created with all class names that might be added to a md
     47        try:
     48            # if results has meaningful data, save the name of the subclass and class instance
     49            NCData.groups['results']
     50            results_subclasses_bandaid(md, NCData, verbose)
     51            # otherwise, ignore
     52        except KeyError:
     53            pass
     54           
     55        NCData.close()
     56        if verbose:
     57            print('Model successfully saved as NCData4')
     58        else: pass
     59           
     60    except Error:
     61        NCData.close()
     62        return Error
     63   
     64
     65def results_subclasses_bandaid(md, NCData, verbose = False):
    6266    # since the results class may have nested classes within it, we need to record the name of the
    6367    # nested class instance variable as it appears in the md that we're trying to save
    6468    quality_control = []
    6569
    66     # we save lists of instances to the netcdf
     70    # we save lists of instances to the NCData
    6771    solutions = []
    6872    solutionsteps = []
     
    7276        if verbose:
    7377            print(class_instance_name)
    74         # for each class instance in results, see which class its from and record that info in the netcdf to recreate structure later
     78        # for each class instance in results, see which class its from and record that info in the NCData to recreate structure later
    7579        # check to see if there is a solutionstep class instance
    7680        if isinstance(md.results.__dict__[class_instance_name],solutionstep):
     
    8993
    9094    if solutionsteps != []:
    91         write_string_to_netcdf(variable_name=str('solutionstep'), address_of_child=solutionsteps, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)
     95        serialize_string(variable_name=str('solutionstep'), address_of_child=solutionsteps, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose)
    9296
    9397    if solutions != []:
    94         write_string_to_netcdf(variable_name=str('solution'), address_of_child=solutions, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)
     98        serialize_string(variable_name=str('solution'), address_of_child=solutions, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose)
    9599
    96100    if resultsdakotas != []:
    97         write_string_to_netcdf(variable_name=str('resultsdakota'), address_of_child=resultsdakotas, group=NetCDF.groups['results'], list=True, NetCDF=NetCDF, verbose=verbose)
     101        serialize_string(variable_name=str('resultsdakota'), address_of_child=resultsdakotas, group=NCData.groups['results'], list=True, NCData=NCData, verbose=verbose)
    98102
    99103   
     
    107111
    108112
    109 def make_NetCDF(filename: str, verbose = False):
     113def create_NCData(filename: str, verbose = False):
    110114    # If file already exists delete / rename it
    111115    if os.path.exists(filename):
     
    122126    else:
    123127        # Otherwise create the file and define it globally so other functions can call it
    124         NetCDF = Dataset(filename, 'w', format='NETCDF4')
    125         NetCDF.history = 'Created ' + time.ctime(time.time())
    126         NetCDF.createDimension('Unlim', None)  # unlimited dimension
    127         NetCDF.createDimension('float', 1)     # single integer dimension
    128         NetCDF.createDimension('int', 1)       # single float dimension
     128        NCData = Dataset(filename, 'w', format='NCData4')
     129        NCData.history = 'Created ' + time.ctime(time.time())
     130        NCData.createDimension('Unlim', None)  # unlimited dimension
     131        NCData.createDimension('float', 1)     # single integer dimension
     132        NCData.createDimension('int', 1)       # single float dimension
    129133   
    130134    if verbose:
    131135        print('Successfully created ' + filename)
    132136
    133     return NetCDF
    134 
    135 
    136 def walk_through_model(md, empty_model, NetCDF, verbose= False):
    137     # Iterate over first layer of md_var attributes and assume this first layer is only classes
     137    return NCData
     138
     139
     140def walk_through_model(md, empty_model, NCData, verbose= False):
     141    # Iterate over first layer of md attributes and assume this first layer is only classes
    138142    for group in md.__dict__.keys():
    139143        address = md.__dict__[group]
    140144        empty_address = empty_model.__dict__[group]
    141         # we need to record the layers of the md so we can save them to the netcdf file
     145        # we need to record the layers of the md so we can save them to the NCData file
    142146        layers = [group]
    143147
    144148        # Recursively walk through subclasses
    145         walk_through_subclasses(address, empty_address, layers, NetCDF, empty_model, verbose)       
    146 
    147 
    148 def walk_through_subclasses(address, empty_address, layers: list, NetCDF, empty_model, verbose = False):
     149        walk_through_subclasses(address, empty_address, layers, NCData, empty_model, verbose)       
     150
     151
     152def walk_through_subclasses(address, empty_address, layers: list, NCData, empty_model, verbose = False):
    149153    # See if we have an object with keys or a not
    150154    try:
     
    155159    if is_object:
    156160        # enter the subclass, see if it has nested classes and/or attributes
    157         # then compare attributes between mds and write to netCDF if they differ
     161        # then compare attributes between mds and write to NCData if they differ
    158162        # if subclass found, walk through it and repeat
    159163        for child in address.__dict__.keys():
     
    165169            address_of_child = address.__dict__[child]
    166170           
    167             # if the current object is a results.<solution> object and has the steps attr it needs special treatment
     171            # if the current object is a results.<solution> object and has nonzero steps attr it needs special treatment
    168172            if isinstance(address_of_child, solution) and len(address_of_child.steps) != 0:
    169                 create_group(address_of_child, current_layer, is_struct = True, NetCDF=NetCDF, verbose = verbose)
     173                create_group(address_of_child, current_layer, is_struct = True, is_special_list = False,  NCData=NCData, verbose = verbose)
     174
     175            # if the current object is a list of objects (currently only filters for lists/arrays of classes)
     176            elif isinstance(address_of_child, list) and len(address_of_child) > 0 and hasattr(address_of_child[0], '__dict__'):
     177                create_group(address_of_child, current_layer, is_struct = False, is_special_list = True, NCData=NCData, verbose = verbose)
    170178
    171179            # if the variable is an array, assume it has relevant data (this is because the next line cannot evaluate "==" with an array)
    172180            elif isinstance(address_of_child, np.ndarray):
    173                 create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)
    174            
    175             # see if the child exists in the empty md. If not, record it in the netcdf
     181                create_group(address_of_child, current_layer, is_struct = False, is_special_list = False,  NCData=NCData, verbose = verbose)
     182           
     183            # see if the child exists in the empty md. If not, record it in the NCData
    176184            else:
    177185                try:
     
    181189                    # if the attributes are identical we don't need to save anything
    182190                    if address_of_child == address_of_child_in_empty_class:
    183                         walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NetCDF, empty_model, verbose)
    184    
    185                     # If it has been modified, record it in the NetCDF file
     191                        walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NCData, empty_model, verbose)
     192   
     193                    # If it has been modified, record it in the NCData file
    186194                    else:
    187                         create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)
    188                         walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NetCDF, empty_model, verbose)
    189    
    190                 except KeyError: # record in netcdf and continue to walk thru md
    191                     walk_through_subclasses(address_of_child, empty_address, current_layer, NetCDF, empty_model, verbose)
    192                     create_group(address_of_child, current_layer, is_struct = False, NetCDF=NetCDF, verbose = verbose)
     195                        create_group(address_of_child, current_layer, is_struct = False, is_special_list = False,  NCData=NCData, verbose = verbose)
     196                        walk_through_subclasses(address_of_child, address_of_child_in_empty_class, current_layer, NCData, empty_model, verbose)
     197   
     198                except KeyError: # record in NCData and continue to walk thru md
     199                    walk_through_subclasses(address_of_child, empty_address, current_layer, NCData, empty_model, verbose)
     200                    create_group(address_of_child, current_layer, is_struct = False, is_special_list = False,  NCData=NCData, verbose = verbose)
    193201    else: pass
    194202
    195203
    196 def create_group(address_of_child, layers, is_struct = False, NetCDF=None, verbose = False):
     204def create_group(address_of_child, layers, is_struct = False, is_special_list = False,  NCData=None, verbose = False):
    197205
    198206    # Handle the first layer of the group(s)
    199207    group_name = layers[0]
     208   
     209    # try to make a group unless the group is already made
    200210    try:
    201         group = NetCDF.createGroup(str(group_name))
     211        group = NCData.createGroup(str(group_name))
    202212    except:
    203         group = NetCDF.groups[str(group_name)]
     213        group = NCData.groups[str(group_name)]
    204214
    205215    # need to check if inversion or m1qn3inversion class
    206216    if group_name == 'inversion':
    207         check_inversion_class(address_of_child, NetCDF, verbose)
     217        check_inversion_class(address_of_child, NCData, verbose)
    208218    else: pass
    209219
    210     # if the data is nested, create nested groups to match class structure
     220    # if the data is nested in md, create nested groups to match class structure
    211221    if len(layers) > 2:
    212222        for name in layers[1:-1]:
     
    214224                group = group.createGroup(str(name))
    215225            except:
    216                 group = NetCDF.groups[str(name)]
     226                group = NCData.groups[str(name)]
    217227    else: pass
    218228
     
    220230    if is_struct:
    221231        parent_struct_name = layers[-1]
    222         copy_nested_results_struct(parent_struct_name, address_of_child, group, NetCDF, verbose)
     232        serialize_nested_results_struct(parent_struct_name, address_of_child, group, NCData, verbose)
     233
     234    elif is_special_list:
     235        list_name = layers[-1]
     236        serialize_array_of_objects(list_name, address_of_child, group, NCData, verbose)
    223237   
    224238    else:
    225239        variable_name = layers[-1]
    226         create_var(variable_name, address_of_child, group, NetCDF, verbose)
     240        serialize_var(variable_name, address_of_child, group, NCData, verbose)
    227241           
    228242
     
    242256
    243257@singleton
    244 def check_inversion_class(address_of_child, NetCDF, verbose = False):
     258def check_inversion_class(address_of_child, NCData, verbose = False):
    245259    # need to make sure that we have the right inversion class: inversion, m1qn3inversion, taoinversion
    246260    if isinstance(address_of_child, m1qn3inversion):
    247         write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('m1qn3inversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)
     261        serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('m1qn3inversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose)
    248262        if verbose:
    249263            print('Successfully saved inversion class instance ' + 'm1qn3inversion')
    250264    elif isinstance(address_of_child, taoinversion):
    251         write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('taoinversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)
     265        serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('taoinversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose)
    252266        if verbose:
    253267            print('Successfully saved inversion class instance ' + 'taoinversion')
    254268    else:
    255         write_string_to_netcdf(variable_name=str('inversion_class_name'), address_of_child=str('inversion'), group=NetCDF.groups['inversion'], NetCDF=NetCDF, verbose = verbose)
     269        serialize_string(variable_name=str('inversion_class_name'), address_of_child=str('inversion'), group=NCData.groups['inversion'], NCData=NCData, verbose = verbose)
    256270        if verbose:
    257271            print('Successfully saved inversion class instance ' + 'inversion')
    258272
    259273
    260 def copy_nested_results_struct(parent_struct_name, address_of_struct, group, NetCDF, verbose = False):
     274def  (parent_struct_name, address_of_struct, group, NCData, verbose = False):
    261275    '''
    262         This function takes a solution class instance and saves the solutionstep instances from <solution>.steps to the netcdf.
     276        This function takes a solution class instance and saves the solutionstep instances from <solution>.steps to the NCData.
    263277
    264278        To do this, we get the number of dimensions (substructs) of the parent struct.
     
    268282    '''
    269283    if verbose:
    270         print("Beginning transfer of nested MATLAB struct to the NetCDF")
     284        print("Beginning transfer of nested MATLAB struct to the NCData")
    271285   
    272286    # make a new subgroup to contain all the others:
     
    274288
    275289    # make sure other systems can flag the nested struct type
    276     write_string_to_netcdf('this_is_a_nested', 'struct', group, list=False, NetCDF=NetCDF, verbose = verbose)
     290    serialize_string('this_is_a_nested', 'struct', group, list=False, NCData=NCData, verbose = verbose)
    277291
    278292    # other systems know the name of the parent struct because it's covered by the results/qmu functions above
     
    290304        for variable in substruct_fields:
    291305            address_of_child = current_substruct.__dict__[variable]
    292             create_var(variable, address_of_child, subgroup, NetCDF, verbose = verbose)
     306            serialize_var(variable, address_of_child, subgroup, NCData, verbose = verbose)
    293307   
    294308    if verbose:
    295         print(f'Successfully transferred struct {parent_struct_name} to the NetCDF\n')
    296    
     309        print(f'Successfully transferred struct {parent_struct_name} to the NCData\n')
     310
     311
     312
     313
     314def serialize_array_of_objects(list_name, address_of_child, group, NCData, verbose):
     315    # Get the dimensions of the cell array
     316    if len(np.shape(address_of_child)) > 1:
     317        rows, cols = np.shape(address_of_child)
     318    else: rows, cols = 1, np.shape(address_of_child)[0]
     319
     320    # Make subgroup to represent the array
     321    name_of_subgroup = f"{str(rows)}x{str(cols)}_cell_array_of_objects"
     322    subgroup = group.createGroup(name_of_subgroup)
     323
     324    # Save the name of the cell array
     325    serialize_string('name_of_cell_array', list_name, subgroup, NCData, verbose)
     326
     327    # Save the dimensions of the cell array
     328    rowsID = subgroup.createVariable('rows', int, ('int',))
     329    colsID = subgroup.createVariable('cols', int, ('int',))
     330    rowsID[:] = rows
     331    colsID[:] = cols
     332
     333
     334    # If this is a multidimensional cell array, iterate over rows here and cols in serialize_objects
     335    if rows > 1:
     336        for row in range(rows):
     337            # Make a subgroup for each row
     338            name_of_subgroup = f"Row_{row+1}_of_{rows}"
     339            subgroup = group.createGroup(name_of_subgroup)
     340            serialize_objects(address_of_child, subgroup, NCData, cols, verbose)
     341    else:
     342        serialize_objects(address_of_child, subgroup, NCData, cols, verbose)
     343
     344
     345
     346def serialize_objects(address_of_child, group, NCData, cols, verbose):
     347    for col in range(cols):
     348        # Make subgroup to contain each col of array
     349        name_of_subgroup = f'Col_{col+1}_of_{cols}'
     350        subgroup = group.createGroup(name_of_subgroup)
     351
     352        # index the current item
     353        variable = address_of_child[col]
     354
     355        # Get the kind of object we're working with:
     356        # see if it's a solution instance
     357        if isinstance(variable, solution) and len(variable.steps) != 0:
     358            pass
     359            # this needs more work...
     360            #name_raw = list(address_of_child[col - 1].keys())[0]
     361            #variable_name = name_raw
     362            #serialize_nested_struct(variable_name, variable, subgroup, NCData, verbose)
    297363       
    298 def create_var(variable_name, address_of_child, group, NetCDF, verbose = False):
     364        # see if it's a general class -- assume ISSM classes all have __dict__
     365        elif hasattr(variable, '__dict__'):
     366            # Handle class instances
     367            serialize_class_instance(variable, subgroup, NCData, verbose)
     368        else:
     369            print('ERROR: Cell arrays of mixed types are not yet supported in read_NCData!')
     370            print('Deserialization will not be able to complete!')
     371            # Handle regular data structures that are already supported
     372            serialize_var(variable_name, variable, subgroup, NCData, verbose)
     373
     374
     375
     376
     377def serialize_class_instance(instance, group, NCData, verbose):
     378    # get parent class name:
     379    name = instance.__class__.__name__
     380
     381    # save the name of the class
     382    serialize_string(variable_name='class_is_a', address_of_child=name, group=group, NCData=NCData, verbose = verbose)
     383
     384    # make subgroup to contain attributes
     385    name_of_subgroup = 'Properties_of_' + name
     386    subgroup = group.createGroup(name_of_subgroup)
     387
     388    # get attributes
     389    keys = instance.__dict__.keys()
     390
     391    for name in keys:
     392        serialize_var(name, instance.__dict__[name], subgroup, NCData, verbose)
     393   
     394
     395
     396       
     397def serialize_var(variable_name, address_of_child, group, NCData, verbose = False):
    299398    # There are lots of different variable types that we need to handle from the md class
    300399   
    301400    # This first conditional statement will catch numpy arrays of any dimension and save them
    302401    if isinstance(address_of_child, np.ndarray):
    303         write_numpy_array_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose=verbose)
     402        serialize_numpy_array(variable_name, address_of_child, group, NCData, verbose=verbose)
    304403   
    305404    # check if it's an int
     
    315414    # or a string
    316415    elif isinstance(address_of_child, str):
    317         write_string_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose=verbose)
     416        serialize_string(variable_name, address_of_child, group, NCData, verbose=verbose)
    318417
    319418    #or a bool
    320419    elif isinstance(address_of_child, bool) or isinstance(address_of_child, np.bool_):
    321         # 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'
     420        # NCData4 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'
    322421        variable = group.createVariable(variable_name, int, ('int',))
    323422        variable[:] = int(address_of_child)
     
    331430    elif isinstance(address_of_child,list) and isinstance(address_of_child[0],str):
    332431        for string in address_of_child:
    333             write_string_to_netcdf(variable_name, string, group, list=True, NetCDF=NetCDF, verbose=verbose)
     432            serialize_string(variable_name, string, group, list=True, NCData=NCData, verbose=verbose)
    334433
    335434    # or a regular list
     
    352451   
    353452    if verbose:
    354         print(f'Successfully transferred data from {variable_name} to the NetCDF')
    355    
    356 
    357 def write_string_to_netcdf(variable_name, address_of_child, group, list=False, NetCDF=None, verbose = False):
    358     # netcdf and strings dont get along.. we have to do it 'custom':
     453        print(f'Successfully transferred data from {variable_name} to the NCData')
     454   
     455
     456def serialize_string(variable_name, address_of_child, group, list=False, NCData=None, verbose = False):
     457    # NCData and strings dont get along.. we have to do it 'custom':
    359458    # if we hand it an address we need to do it this way:
    360459    if list == True:
    361460        """
    362         Save a list of strings to a NetCDF file.
     461        Save a list of strings to a NCData file.
    363462   
    364463        Convert a list of strings to a numpy.char_array with utf-8 encoded elements
    365         and size rows x cols with each row the same # of cols and save to NetCDF
     464        and size rows x cols with each row the same # of cols and save to NCData
    366465        as char array.
    367466        """
     
    399498                arr[i] = new_list[i]
    400499   
    401             # save array to netcdf file
     500            # save array to NCData file
    402501            string_var[:] = arr
    403502
     
    412511        length_of_the_string = len(the_string_to_save)
    413512        numpy_datatype = 'S' + str(length_of_the_string)
    414         str_out = netCDF4.stringtochar(np.array([the_string_to_save], dtype=numpy_datatype))       
     513        str_out = NCData4.stringtochar(np.array([the_string_to_save], dtype=numpy_datatype))       
    415514   
    416515        # we'll need to make a new dimension for the string if it doesn't already exist
     
    431530
    432531
    433 def write_numpy_array_to_netcdf(variable_name, address_of_child, group, NetCDF, verbose = False):
    434     # to make a nested array in netCDF, we have to get the dimensions of the array,
    435     # create corresponding dimensions in the netCDF file, then we can make a variable
    436     # in the netCDF with dimensions identical to those in the original array
     532def serialize_numpy_array(variable_name, address_of_child, group, NCData, verbose = False):
     533    # to make a nested array in NCData, we have to get the dimensions of the array,
     534    # create corresponding dimensions in the NCData file, then we can make a variable
     535    # in the NCData with dimensions identical to those in the original array
    437536   
    438537    # start by getting the data type at the lowest level in the array:
Note: See TracChangeset for help on using the changeset viewer.