Changeset 27899


Ignore:
Timestamp:
09/06/23 20:15:43 (19 months ago)
Author:
musselman
Message:

Enhanced readability in python files. Added try/except block at start of program to prevent file corruption.

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

Legend:

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

    r27898 r27899  
    2828def read_netCDF(filename, verbose = False):
    2929    if verbose:
    30         print('NetCDF42C v1.1.13')
     30        print('NetCDF42C v1.2.0')
     31
     32    '''
     33    filename = path and name to save file under
     34    verbose = T/F = show or muted log statements. Naturally muted
     35    '''
    3136
    3237    # this is a precaution so that data is not lost
     
    4348            NCData.set_auto_mask(False)
    4449        else:
    45             print('The file you entered does not exist or cannot be found in the current directory')
    46             return print()
     50            return 'The file you entered does not exist or cannot be found in the current directory'
    4751       
    48         # continuation of band-aid for results class
     52        # in order to handle some subclasses in the results class, we have to utilize this band-aid
     53        # 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
    4954        try:
     55            # if results has meaningful data, save the name of the subclass and class instance
    5056            NCData.groups['results']
    5157            make_results_subclasses(NCData, verbose)
     
    7682        return model_copy
    7783
    78     except Error:
    79         NCData.close()
    80         return Error
    81 
     84    # just in case something unexpected happens
     85    except Exception as e:
     86        if 'NCData' in locals():
     87            NCData.close()
     88        raise e
    8289
    8390def make_results_subclasses(NCData, verbose = False):
     
    123130    # first, we enter the group by: filename.groups['group_name']
    124131    # second we search the current level for variables: filename.groups['group_name'].variables.keys()
    125     # at this step we check for multidimensional structure arrays and filter them out
     132    # at this step we check for multidimensional structure arrays/ arrays of objects and filter them out
    126133    # third we get nested group keys by: filename.groups['group_name'].groups.keys()
    127     # if a variables exists, copy the data to the model framework by calling copy function
    128134    # if a nested groups exist, repeat all
    129135
     
    170176
    171177
     178
     179'''
     180    MATLAB has Multidimensional Structure Arrays in 2 known classes: results and qmu.
     181    The python classes results.py and qmu.py emulate this MATLAB object in their own
     182    unique ways. The functions in this script will assign data to either of these
     183    classes such that the final structure is compatible with its parent class.
     184'''
     185
     186def deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False):
     187    '''
     188    A common multidimensional array is the 1xn md.results.TransientSolution object.
     189
     190    The way that this object emulates the MATLAB mutli-dim. struct. array is with
     191    the solution().steps attr. which is a list of solutionstep() instances
     192        The process to recreate is as follows:
     193            1. Get instance of solution() with solution variable (the instance is made in make_results_subclasses)
     194            2. For each subgroup, create a solutionstep() class instance
     195             2a. Populate the instance with the key:value pairs
     196             2b. Append the instance to the solution().steps list
     197    '''
     198    # step 1
     199    class_instance_name = name_of_struct
     200   
     201    # for some reason steps is not already a list
     202    setattr(model_copy.results.__dict__[class_instance_name], 'steps', list())
     203
     204    steps = model_copy.results.__dict__[class_instance_name].steps
     205   
     206    # step 2
     207    layer = 1
     208    for subgroup in eval(group_location_in_file + ".groups.keys()"):
     209        solutionstep_instance = solutionstep()
     210        # step 2a
     211        subgroup_location_in_file = group_location_in_file + ".groups['" + subgroup + "']"
     212        for key in eval(subgroup_location_in_file + ".variables.keys()"):
     213            value = eval(subgroup_location_in_file + ".variables['" + str(key) + "'][:]")
     214            setattr(solutionstep_instance, key, value)
     215        # step 2b
     216        steps.append(solutionstep_instance)
     217        if verbose:
     218            print('Succesfully loaded layer ' + str(layer) + ' to results.' + str(class_instance_name) + ' struct.')
     219        else: pass
     220        layer += 1
     221
     222    if verbose:
     223        print('Successfully recreated results structure ' + str(class_instance_name))
     224
     225
     226
    172227def deserialize_array_of_objects(group_location_in_file, model_copy, NCData, verbose):
    173228    '''
     
    193248        original structure when the model was saved
    194249    '''
     250
     251    if verbose:
     252        print(f"Loading array of objects.")
    195253
    196254    # get the name_of_cell_array, rows and cols vars
     
    231289                if "class_is_a" in current_col_vars:
    232290                    class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode()
    233                     col_data = deserialize_class(class_name, columns.groups[str(col)], NCData, verbose)
     291                    col_data = deserialize_class_instance(class_name, columns.groups[str(col)], NCData, verbose)
    234292                    is_object = True
    235293                elif "this_is_a_nested" in current_col_vars:
     
    267325            if "class_is_a" in current_col_vars:
    268326                class_name = subgroups[str(col)].variables['class_is_a'][:][...].tobytes().decode()
    269                 col_data = deserialize_class(class_name, subgroups[str(col)], NCData, verbose)
     327                col_data = deserialize_class_instance(class_name, subgroups[str(col)], NCData, verbose)
    270328                is_object = True
    271329            elif "this_is_a_nested" in current_col_vars:
     
    288346
    289347    # finally, add the attribute to the model
    290     # borrow some code from above:
    291348    pattern = r"\['(.*?)'\]"
    292349    matches = re.findall(pattern, group_location_in_file)
     
    294351    setattr(model_copy.__dict__[variable_name], name_of_cell_array, array)
    295352
    296 
    297 
    298 def deserialize_class(class_name, group, NCData, verbose=False):
    299 
     353    if verbose:
     354        print(f"Successfully loaded array of objects: {name_of_cell_array} to {variable_name}")
     355
     356
     357
     358def deserialize_class_instance(class_name, group, NCData, verbose=False):
     359
     360    if verbose:
     361        print(f"Loading class: {class_name}")
     362
     363    # this function requires the class module to be imported into the namespace of this file.
     364    # we make a custom error in case the class module is not in the list of imported classes.
    300365    # most ISSM classes are imported by from <name> import <name>
    301366    class ModuleError(Exception):
     
    333398        # Not supported
    334399        pass
    335        
     400
     401    if verbose:
     402        print(f"Successfully loaded class instance {class_name} to model")
    336403    return class_instance
    337404
    338 
    339 
    340 '''
    341     MATLAB has Multidimensional Structure Arrays in 2 known classes: results and qmu.
    342     The python classes results.py and qmu.py emulate this MATLAB object in their own
    343     unique ways. The functions in this script will assign data to either of these
    344     classes such that the final structure is compatible with its parent class.
    345 '''
    346 
    347 def deserialize_nested_results_struct(group_location_in_file, name_of_struct, NCData, verbose = False):
    348     '''
    349     A common multidimensional array is the 1xn md.results.TransientSolution object.
    350 
    351     The way that this object emulates the MATLAB mutli-dim. struct. array is with
    352     the solution().steps attr. which is a list of solutionstep() instances
    353         The process to recreate is as follows:
    354             1. Get instance of solution() with solution variable (the instance is made in make_results_subclasses)
    355             2. For each subgroup, create a solutionstep() class instance
    356              2a. Populate the instance with the key:value pairs
    357              2b. Append the instance to the solution().steps list
    358     '''
    359     # step 1
    360     class_instance_name = name_of_struct
    361    
    362     # for some reason steps is not already a list
    363     setattr(model_copy.results.__dict__[class_instance_name], 'steps', list())
    364 
    365     steps = model_copy.results.__dict__[class_instance_name].steps
    366    
    367     # step 2
    368     layer = 1
    369     for subgroup in eval(group_location_in_file + ".groups.keys()"):
    370         solutionstep_instance = solutionstep()
    371         # step 2a
    372         subgroup_location_in_file = group_location_in_file + ".groups['" + subgroup + "']"
    373         for key in eval(subgroup_location_in_file + ".variables.keys()"):
    374             value = eval(subgroup_location_in_file + ".variables['" + str(key) + "'][:]")
    375             setattr(solutionstep_instance, key, value)
    376         # step 2b
    377         steps.append(solutionstep_instance)
    378         if verbose:
    379             print('Succesfully loaded layer ' + str(layer) + ' to results.' + str(class_instance_name) + ' struct.')
    380         else: pass
    381         layer += 1
    382 
    383     if verbose:
    384         print('Successfully recreated results structure ' + str(class_instance_name))
    385405
    386406
     
    434454
    435455def deserialize_dict(location_of_variable_in_file, location_of_variable_in_model, NCData, verbose = False):
    436     # as simple as navigating to the location_of_variable_in_model and setting it equal to the location_of_variable_in_file
    437 
    438     # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those
    439456    FillValue = -9223372036854775806
    440457
  • issm/trunk/src/m/contrib/musselman/write_netCDF.py

    r27898 r27899  
    11# imports
    2 import NCData4
    3 from NCData4 import Dataset
     2import netCDF4
     3from netCDF4 import Dataset
    44import numpy as np
    55import numpy.ma as ma
     
    2323
    2424
    25 def write_NCData(md, filename: str, verbose = False):
     25def write_netCDF(md, filename: str, verbose = False):
    2626    if verbose:
    27         print('Python C2NCData4 v1.1.14')
     27        print('Python C2NetCDF4 v1.2.0')
    2828    else: pass
    2929    '''
    30     md = model() class instance to be saved
     30    md = model class instance to be saved
    3131    filename = path and name to save file under
    32     verbose = T/F muted or show log statements. Naturally muted
     32    verbose = T/F = show or muted log statements. Naturally muted
    3333    '''
    3434    # this is a precaution so that data is not lost
    3535    try:
    3636        # Create a NCData file to write to
    37         NCData = create_NCData(filename, verbose)
     37        NCData = create_NetCDF(filename, verbose)
    3838       
    3939        # Create an instance of an empty md class to compare md_var against
     
    5555        NCData.close()
    5656        if verbose:
    57             print('Model successfully saved as NCData4')
     57            print('Model successfully saved as NetCDF4')
    5858        else: pass
    59            
    60     except Error:
    61         NCData.close()
    62         return Error
     59
     60    # just in case something unexpected happens
     61    except Exception as e:
     62        if 'NCData' in locals():
     63            NCData.close()
     64        raise e
    6365   
    6466
     
    111113
    112114
    113 def create_NCData(filename: str, verbose = False):
     115def create_NetCDF(filename: str, verbose = False):
    114116    # If file already exists delete / rename it
    115117    if os.path.exists(filename):
     
    126128    else:
    127129        # Otherwise create the file and define it globally so other functions can call it
    128         NCData = Dataset(filename, 'w', format='NCData4')
     130        NCData = Dataset(filename, 'w', format='NETCDF4')
    129131        NCData.history = 'Created ' + time.ctime(time.time())
    130132        NCData.createDimension('Unlim', None)  # unlimited dimension
     
    272274
    273275
    274 def  (parent_struct_name, address_of_struct, group, NCData, verbose = False):
     276def serialize_nested_results_struct(parent_struct_name, address_of_struct, group, NCData, verbose = False):
    275277    '''
    276         This function takes a solution class instance and saves the solutionstep instances from <solution>.steps to the NCData.
    277 
    278         To do this, we get the number of dimensions (substructs) of the parent struct.
     278        This function takes a results.solution class instance and saves the solutionstep instances from <solution>.steps to the NCData.
     279
     280        To do this, we get the number of dimensions (substructs) of the parent struct (list).
    279281        Next, we iterate through each substruct and record the data.
    280282        For each substruct, we create a subgroup of the main struct.
     
    313315
    314316def serialize_array_of_objects(list_name, address_of_child, group, NCData, verbose):
     317    if verbose:
     318        print(f"Serializing array of objects.")
     319   
    315320    # Get the dimensions of the cell array
    316321    if len(np.shape(address_of_child)) > 1:
     
    341346    else:
    342347        serialize_objects(address_of_child, subgroup, NCData, cols, verbose)
    343 
     348       
     349    if verbose:
     350        print(f"Successfully serialized array of objects: {list_name}")
    344351
    345352
     
    358365            pass
    359366            # 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)
    363367       
    364368        # see if it's a general class -- assume ISSM classes all have __dict__
     
    373377
    374378
    375 
    376 
    377379def serialize_class_instance(instance, group, NCData, verbose):
    378380    # get parent class name:
     
    418420    #or a bool
    419421    elif isinstance(address_of_child, bool) or isinstance(address_of_child, np.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'
     422        # NetCDF 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'
    421423        variable = group.createVariable(variable_name, int, ('int',))
    422424        variable[:] = int(address_of_child)
     
    457459    # NCData and strings dont get along.. we have to do it 'custom':
    458460    # if we hand it an address we need to do it this way:
    459     if list == True:
    460         """
    461         Save a list of strings to a NCData file.
    462    
     461    if list:
     462        """   
    463463        Convert a list of strings to a numpy.char_array with utf-8 encoded elements
    464464        and size rows x cols with each row the same # of cols and save to NCData
     
    511511        length_of_the_string = len(the_string_to_save)
    512512        numpy_datatype = 'S' + str(length_of_the_string)
    513         str_out = NCData4.stringtochar(np.array([the_string_to_save], dtype=numpy_datatype))       
     513        str_out = netCDF4.stringtochar(np.array([the_string_to_save], dtype=numpy_datatype))       
    514514   
    515515        # we'll need to make a new dimension for the string if it doesn't already exist
Note: See TracChangeset for help on using the changeset viewer.