Changeset 27858


Ignore:
Timestamp:
07/26/23 12:04:55 (20 months ago)
Author:
musselman
Message:

Modified read/write_netCDF_commit.py files to work with bool/numpy datatypes

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

Legend:

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

    r27838 r27858  
    3333        # remove masks from numpy arrays for easy conversion
    3434        NCData.set_auto_mask(False)
     35    else:
     36        print('The file you entered does not exist or cannot be found in the current directory')
    3537   
    36 
    37     # read the contents of the groups
    38 
    39     '''
    40     this function navigates like:
    41 
    42     filename.groups.keys() -> filename.groups['group1'] ->
    43     filename.groups['group1'].groups.keys() -> filename.groups['group1'].groups['group1.1'] ->
    44     filename.groups['group1'].groups['group1.1'].groups.keys() ->
    45     filename.groups['group1'].groups['group1.1'].groups['group1.1.1'] etc. etc.
    46     '''
    4738    # continuation of band-aid for results class
    4839    try:
     
    6354def make_results_subclasses():
    6455    for subclass in NCData.groups['results'].variables.keys():
    65         class_instance = subclass
     56        class_instance = subclass + '()'
    6657        class_instance_name = NCData.groups['results'].variables[subclass][:][...].tobytes().decode()
     58        print(class_instance)
     59        print(class_instance_name)
    6760        setattr(model_copy.results, class_instance_name, eval(class_instance))
    6861
     
    9790    # NetCDF4 has a property called "_FillValue" that sometimes saves empty lists, so we have to catch those
    9891    FillValue = -9223372036854775806
    99    
    100     # but there are a couple of cases we need to compensate for, like an arrary of a single integer should just be an integer and not an array
    101     if len(eval(location_of_variable_in_file))>1:
    102         setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
     92
     93    # results band-aid...
     94    if str(location_of_variable_in_model + '.' + variable_name) =='results.solutionstep':
     95        pass
    10396    # handle any strings:
    104     if 'char' in eval(location_of_variable_in_file + '.dimensions[0]'):
     97    elif 'char' in eval(location_of_variable_in_file + '.dimensions[0]'):
    10598        setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:][...].tobytes().decode()'))
    106     # catch everything else (lists, 1-D arrays, etc.)
     99    # handle ndarrays + lists
     100    elif len(eval(location_of_variable_in_file + '[:]'))>1:
     101        # check for bool
     102        try: # there is only one datatype assigned the attribute 'units' and that is bool, so anything else will go right to except
     103            if eval(location_of_variable_in_file + '.units') == 'bool':
     104                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, np.array(eval(location_of_variable_in_file + '[:]'), dtype = bool))
     105            else:
     106                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
     107        except:
     108            setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
     109    # catch everything else
    107110    else:
    108         # check for FillValue. use try/except because try block will only work on datatypes than like int64, float, single element lists/arrays ect and not nd-arrays/n-lists etc
    109         print(eval(location_of_variable_in_file + '[:][0]'))
     111        # check for FillValue. use try/except because try block will only work on datatypes like int64, float, single element lists/arrays ect and not nd-arrays/n-lists etc
    110112        try:
     113            # this try block will only work on single ints/floats/doubles and will skip to the except block for all other cases
    111114            if FillValue == eval(location_of_variable_in_file + '[:][0]'):
    112115                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, [])
     116            else:
     117                # we have to convert numpy datatypes to native python types with .item()
     118                var_to_save = eval(location_of_variable_in_file + '[:][0]')  # note the [0] on the end
     119                setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, var_to_save.item())
    113120        except:
    114             setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:][0]')) # note the [0] on the end
    115        
     121            setattr(eval('model_copy.' + location_of_variable_in_model), variable_name, eval(location_of_variable_in_file + '[:]'))
    116122    print('Successfully saved ' + location_of_variable_in_model + '.' + variable_name + ' to model.')
    117123
  • issm/trunk/src/m/contrib/musselman/write_netCDF_commit.py

    r27838 r27858  
    8888   
    8989        # If so, inqure for a new name or to do delete the existing file
    90         newname = input('Give a new name or "delete" to replace: ')
     90        newname = input('Give a new name or input "delete" to replace: ')
    9191
    9292        if newname == 'delete':
     
    131131            # in the framework of an empty model. If this is the case, we move to the except statement
    132132            try:
    133                 if type(child) == type(eval(adress_of_child_in_empty_class)):
     133                # if the variable is an array, assume it has relevant data
     134                if isinstance(eval(adress_of_child), np.ndarray):
     135                    create_group(model_var, adress_of_child)
     136                    walk_through_subclasses(model_var, adress_of_child, model_name)
     137                elif eval(adress_of_child) == eval(adress_of_child_in_empty_class):
    134138                    walk_through_subclasses(model_var, adress_of_child, model_name)
    135139                # If it has been modified, record it in the NetCDF file
     
    172176   
    173177    # check if it's an int
    174     elif isinstance(eval(adress_of_child), int):
     178    elif isinstance(eval(adress_of_child), int) or isinstance(eval(adress_of_child), np.integer):
    175179        variable = group.createVariable(variable_name, int, ('int',))
    176180        variable[:] = eval(adress_of_child)
    177181   
    178182    # or a float
    179     elif isinstance(eval(adress_of_child), float):
     183    elif isinstance(eval(adress_of_child), float) or isinstance(eval(adress_of_child), np.floating):
    180184        variable = group.createVariable(variable_name, float, ('float',))
    181185        variable[:] = eval(adress_of_child)
     
    184188    elif isinstance(eval(adress_of_child), str):
    185189        write_string_to_netcdf(variable_name, adress_of_child, group)
     190
     191    #or a bool
     192    elif isinstance(eval(adress_of_child), bool) or isinstance(eval(adress_of_child), np.bool):
     193        # 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'
     194        variable = group.createVariable(variable_name, int, ('int',))
     195        variable[:] = int(eval(adress_of_child))
     196        variable.units = "bool"
    186197       
    187198    # or an empty list
     
    192203    elif isinstance(eval(adress_of_child),list) and isinstance(eval(adress_of_child)[0],str):
    193204        for string in eval(adress_of_child):
    194             write_string_to_netcdf(variable_name, string, group)
     205            write_string_to_netcdf(variable_name, string, group, list=True)
    195206
    196207    # or a regular list
    197208    elif isinstance(eval(adress_of_child), list):
     209        print('made list w/ unlim dim')
    198210        variable = group.createVariable(variable_name, type(eval(adress_of_child)[0]), ('Unlim',))
    199211        variable[:] = eval(adress_of_child)
     
    204216            variable = group.createVariable(variable_name, type(eval(adress_of_child)), ('Unlim',))
    205217            variable[:] = eval(adress_of_child)
     218            print('Used Unlim Dim')
    206219        except Exception as e:
    207220            print(e)
     
    212225
    213226
    214 
    215 def write_string_to_netcdf(variable_name, adress_of_child, group):
     227def write_string_to_netcdf(variable_name, adress_of_child, group, list=False):
    216228    # netcdf and strings dont get along.. we have to do it 'custom':
    217229    # if we hand it an adress we need to do it this way:
     
    233245        group.createDimension(name_of_dimension, length_of_the_string)
    234246    except: pass
    235     # now we can make a variable in this dimension:
    236     string = group.createVariable(variable_name, 'S1', (name_of_dimension))
    237     #finally we can write the variable:
    238     string[:] = str_out
     247    # this is another band-aid to the results sub classes...
     248    try:
     249        if list == True:
     250            # now we can make a variable in this dimension:
     251            string = group.createVariable(variable_name, 'S1', (name_of_dimension))
     252            #finally we can write the variable:
     253            string[:] = [str_out]
     254        else:
     255            # now we can make a variable in this dimension:
     256            string = group.createVariable(variable_name, 'S1', (name_of_dimension))
     257            #finally we can write the variable:
     258            string[:] = str_out
     259    except RuntimeError: pass
     260    except Exception:
     261        print(Exception)
    239262
    240263
     
    246269    # start by getting the data type at the lowest level in the array:
    247270    typeis = eval(adress_of_child + '.dtype')
    248    
    249     # if the array is 1D, we don't need to do anything fancy
    250     # sometimes an array has just 1 element in it though, so we need to account for those cases here:
    251     if len(eval(adress_of_child)) == 1:
    252         if typeis is np.dtype('float64'):
    253             variable = group.createVariable(variable_name, typeis, ('float',))
    254             variable[:] = eval(adress_of_child)           
    255         elif typeis is np.dtype('int64'):
    256             variable = group.createVariable(variable_name, typeis, ('int',))
    257             variable[:] = eval(adress_of_child)           
     271
     272    # catch boolean arrays here
     273    if typeis == bool:
     274        # sometimes an array has just 1 element in it, we account for those cases here:
     275        if len(eval(adress_of_child)) == 1:
     276            variable = group.createVariable(variable_name, int, ('int',))
     277            variable[:] = int(eval(adress_of_child))
     278            variable.units = "bool"
    258279        else:
    259             variable = group.createVariable(variable_name, typeis, ('Unlim',))
     280            # make the dimensions
     281            dimensions = []
     282            for dimension in np.shape(eval(adress_of_child)):
     283                dimensions.append(str('dim' + str(dimension)))
     284                # if the dimension already exists we can't have a duplicate
     285                try:
     286                    group.createDimension(str('dim' + str(dimension)), dimension)
     287                except: pass # this would mean that the dimension already exists
     288   
     289            # create the variable:
     290            variable = group.createVariable(variable_name, int, tuple(dimensions))
     291            # write the variable:
     292            variable[:] = eval(adress_of_child + '.astype(int)')
     293            variable.units = "bool"
     294
     295           
     296           
     297    # handle all other datatypes here
     298    else:
     299        # sometimes an array has just 1 element in it, we account for those cases here:
     300        if len(eval(adress_of_child)) == 1:
     301            if typeis is np.dtype('float64'):
     302                variable = group.createVariable(variable_name, typeis, ('float',))
     303                variable[:] = eval(adress_of_child)           
     304            elif typeis is np.dtype('int64'):
     305                variable = group.createVariable(variable_name, typeis, ('int',))
     306                variable[:] = eval(adress_of_child)           
     307            else:
     308                print('Encountered single datatype that was not float64 or int64, saving under unlimited dimension, may cause errors.')
     309                variable = group.createVariable(variable_name, typeis, ('Unlim',))
     310                variable[:] = eval(adress_of_child)
     311   
     312        # This catches all arrays/lists:
     313        else:
     314            # make the dimensions
     315            dimensions = []
     316            for dimension in np.shape(eval(adress_of_child)):
     317                dimensions.append(str('dim' + str(dimension)))
     318                # if the dimension already exists we can't have a duplicate
     319                try:
     320                    group.createDimension(str('dim' + str(dimension)), dimension)
     321                except: pass # this would mean that the dimension already exists
     322   
     323            # create the variable:
     324            variable = group.createVariable(variable_name, typeis, tuple(dimensions))
     325   
     326            # write the variable:
    260327            variable[:] = eval(adress_of_child)
    261    
    262     # this is the 1D case:
    263     elif len(np.shape(eval(adress_of_child))) == 1:
    264         variable = group.createVariable(variable_name, typeis, ('Unlim',))
    265         variable[:] = eval(adress_of_child)
    266    
    267     # But if the array is >1D, we do need to be fancy:
    268     else:
    269         # make the dimensions
    270         dimensions = []
    271         for dimension in np.shape(eval(adress_of_child)):
    272             dimensions.append(str('dim' + str(dimension)))
    273             # if the dimension already exists we can't have a duplicate
    274             try:
    275                 group.createDimension(str('dim' + str(dimension)), dimension)
    276             except: pass # this would mean that the dimension already exists
    277 
    278         # create the variable:
    279         variable = group.createVariable(variable_name, typeis, tuple(dimensions))
    280 
    281         # write the variable:
    282         variable[:] = eval(adress_of_child)
Note: See TracChangeset for help on using the changeset viewer.